340 Commits
1.2.x ... tip

Author SHA1 Message Date
Mitchell Hashimoto
f41e61cd31 nuke ziglyph from orbit (#8978)
Since we now use uucode, we don't need ziglyph anymore. Ziglyph was kept
around as a test-only dep so we can verify matching but this is
complicating our Zig 0.15 upgrade because ziglyph doesn't support Zig
0.15. Let's just drop it.

cc @jacobsandlund
2025-09-30 12:22:10 -07:00
Mitchell Hashimoto
16deea2761 nuke ziglyph from orbit
Since we now use uucode, we don't need ziglyph anymore. Ziglyph was kept
around as a test-only dep so we can verify matching but this is
complicating our Zig 0.15 upgrade because ziglyph doesn't support Zig
0.15. Let's just drop it.
2025-09-30 12:17:10 -07:00
Mitchell Hashimoto
ceac472af0 Revert "renderer: slightly optimize screen copy" (#8974)
This reverts commit fcea09e413 because it
appears to be causing memory leaks.
2025-09-30 09:29:00 -07:00
Jeffrey C. Ollie
86fb03677a Revert "renderer: slightly optimize screen copy"
This reverts commit fcea09e413.
2025-09-30 11:07:25 -05:00
Mitchell Hashimoto
150fb18ca1 Inline All The Things (#8946)
I used the new CPU counter mode in Instruments.app to track down
functions that had instruction delivery bottlenecks (indicating i-cache
misses) and picked a bunch of trivial functions to mark as inline (plus
a couple that are only used once or twice and which benefit from
inlining).

The size of `macos-arm64/libghostty-fat.a` built with `zig build
-Doptimize=ReleaseFast -Dxcframework-target=native` goes from
`145,538,856` bytes on `main` to `145,595,952` on this branch, a
negligible increase.

These changes resulted in some pretty sizable improvements in vtebench
results on my machine (Apple M3 Max):
<img width="983" height="696" alt="image"
src="https://github.com/user-attachments/assets/cac595ca-7616-48ed-983c-208c2ca2023f"
/>

With this, the only vtebench test we're slower than Alacritty in (on my
machine, at 130x51 window size) is `dense_cells` (which, IMO, is so
artificial that optimizing for it might actually negatively impact real
world performance).

I also did a pretty simple improvement to how we copy the screen in the
renderer, gave it its own page pool for less memory churn. Further
optimization in that area should be explored since in some scenarios it
seems like as much as 35% of the time on the `io-reader` thread is spent
waiting for the lock.

> [!NOTE]
> Before this is merged, someone really ought to test this on an x86
processor to see how the performance compares there, since this *is*
tuning for my processor specifically, and I know that M chips have
pretty big i-cache compared to some x86 processors which could impact
the performance characteristics of these changes.
2025-09-30 08:13:39 -07:00
Qwerasd
c57c205672 fix test failures
Very weird failures, not 100% sure of the cause; regardless, this fixes
them.
2025-09-30 07:27:40 -07:00
Qwerasd
0388a2b396 terminal: inline all the things
A whole bunch of inline annotations, some of these were tracked down
with Instruments.app, others are guesses / just seemed right because
they were trivial wrapper functions.

Regardless, these changes are ultimately supported by improved vtebench
results on my machine (Apple M3 Max).
2025-09-30 07:27:40 -07:00
Qwerasd
43dd712053 termio: make trivial stream handler callbacks inline
Supported by benchmarks (vtebench on Apple M3 Max)
2025-09-30 07:27:40 -07:00
Qwerasd
4136c469fa datastruct: make trivial linked list ops inline
Supported by benchmarks (vtebench on Apple M3 Max)
2025-09-30 07:27:40 -07:00
Qwerasd
fcea09e413 renderer: slightly optimize screen copy
Changes it so that the renderer retains its own MemoryPool for PageList
pages so that new pages rarely need to be allocated when cloning the
screen. Also switches to using an arena allocator in `updateFrame` to
avoid having to deinit the cloned screen since instead we can just throw
out the memory.
2025-09-30 07:27:40 -07:00
Mitchell Hashimoto
31a4568193 lib-vt: Add SemanticVersion to provide SONAME versions (#8938)
- Provide SONAME versioned shared libraries with major version numbers
to separate ABI breaks

Adding a SemanticVersion to the shared library's module generates
symlings for `libghostty-vt.so.<major version>` and
`libghostty-vt.so.<major>.<minor>`

```
> zig build
> ls zig-out/lib/
libghostty-vt.so@  libghostty-vt.so.0@  libghostty-vt.so.0.1.0*
> readelf -d zig-out/lib/libghostty-vt.so

Dynamic section at offset 0x452858 contains 25 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]
 0x000000000000000e (SONAME)             Library soname: [libghostty-vt.so.0]
...
 ```

Major versions are important for allowing multiple versions of a library to co-exist and let the SONAME section in an ELF binary request a specific major version of a shared library.[^1]

I believe the rules for updating SONAME versions match the SemVer spec for ABI changes.

> 1.    MAJOR version when you make incompatible API changes
> 2.    MINOR version when you add functionality in a backward compatible manner
> 3.    PATCH version when you make backward compatible bug fixes
[^2]

[^1]: https://www.man7.org/conf/lca2006/shared_libraries/slide5d.html 
[^2]: https://semver.org/#summary
2025-09-30 07:18:23 -07:00
azhn
837ac9be77 lib-vt: Add SemanticVersion to module
- Provide SONAME versioned shared libraries with major version numbers
to separate ABI breaks
2025-09-30 07:17:31 -07:00
Mitchell Hashimoto
0cc3728803 macOS: Focus Terminal App Intent (#8961)
Closes #8791 
Discussion: #8657 

### Summary
This adds the FocusTerminalIntent App Intent and related function
(focusSurface), allows external tools (such as Shortcuts/Siri) to
programmatically move focus to a specific terminal window or tab.

### Verification
This functionality has been tested across following scenarios,
confirming correct focus behavior for:

- Split Window
- Tab Group
- Quick Terminal

### Note
It is not supported to move focus to a split that is hidden by a zoomed
split. The same applies to the CloseTerminalIntent.

### AI Disclosure
This pull request was made with assistance from Claude Code.
I reviewed all AI-generated code and wrote the final output manually.
2025-09-30 06:55:49 -07:00
Mitchell Hashimoto
45e61b1a17 update deps files 2025-09-30 06:55:14 -07:00
Mitchell Hashimoto
6da3727431 deps: Replace ziglyph with uucode (#8757)
This replaces `ziglyph` with
[uucode](https://github.com/jacobsandlund/uucode), maintaining the
Ghostty unicode props and symbols tables, but now built with `uucode`
and Unicode 16.

See the above `uucode` repository for a description of the library, but
the short summary is that it aims to be a fast and flexible Unicode
library in Zig, that is very configurable during build time.

This PR adds tests to make sure that the symbol and props tables match
the previous built-by-ziglyph implementation (minus differences in
Unicode 16).

## Benchmarks

Also added are benchmarks comparing the Ghostty tables with `uucode`,
with the following results (MacBook Pro 2021 M1 16 GB).

Summary:

| Benchmark | Dataset | Table Time (ms) | uucode Time (ms) | Fastest |
Fastest Speedup |

|-----------|---------|-----------------|------------------|---------|----------------|
| codepoint-width | data.txt | 929.3 (± 2.3) | 924.1 (± 0.9) | uucode |
1.01x |
| | Arabic | 2,652.0 (± 21.0) | 2,589.0 (± 8.0) | uucode | 1.02x |
| | Japanese | 2,302.0 (± 1.0) | 2,250.0 (± 2.0) | uucode | 1.02x |
| | English | 1,770.0 (± 5.0) | 1,770.0 (± 5.0) | tie | 1.00x |
| grapheme-break | data.txt | 974.5 (± 1.2) | 977.4 (± 0.7) | table |
1.00x |
| | Arabic | 4,135.0 (± 22.0) | 4,037.0 (± 9.0) | uucode | 1.02x |
| | Japanese | 3,537.0 (± 3.0) | 3,459.0 (± 1.0) | uucode | 1.02x |
| | English | 4,799.0 (± 4.0) | 5,119.0 (± 2.0) | table | 1.07x |
| is-symbol | data.txt | 877.9 (± 2.0) | 883.5 (± 1.5) | table | 1.01x |
| | Arabic | 2,735.0 (± 8.0) | 2,611.0 (± 1.0) | uucode | 1.05x |
| | Japanese | 2,391.0 (± 2.0) | 2,276.0 (± 4.0) | uucode | 1.05x |
| | English | 2,450.0 (± 5.0) | 2,212.0 (± 2.0) | uucode | 1.11x |

Sources:

```
# data.txt
zig-out/bin/ghostty-gen +utf8 | head -c 200000000 > data.txt

# Arabic
curl -L "https://www.dropbox.com/scl/fi/86gjpfzopssavk2nzo69u/arwiki-20180920-corpus.xml.bz2?dl=1&e=1&file_subpath=%2Fdata&rlkey=dmjlaw1xegg8vsje4xrn040v8" | bzcat | head -c 1000000000 > arwiki-20180920-corpus.xml

# Japanese
curl -L "https://www.dropbox.com/scl/fi/vru4zxv5qff1klod9xiht/jawiki-20181001-corpus.xml.bz2?rlkey=utuuooiwyupws3x5517u8n8jl&e=1&dl=1" | bzcat | head -c 1000000000 > jawiki-20181001-corpus.xml

# English
curl -L "https://www.dropbox.com/scl/fi/la1nvupgk2honb3n6m9zc/enwiki-20181001-corpus.xml.bz2?rlkey=8vg4vokbaijh1lg5lw3ytc864&e=1&dl=1" | bzcat | head -c 1000000000 > enwiki-20181001-corpus.xml
```

### codepoint-width

data.txt

```
hyperfine --warmup 4 'zig-out/bin/ghostty-bench +codepoint-width --data=data.txt --mode=table' 'zig-out/bin/ghostty-bench +codepoint-width --data=data.txt --mode=uucode'
Benchmark 1: zig-out/bin/ghostty-bench +codepoint-width --data=data.txt --mode=table
  Time (mean ± σ):     929.3 ms ±   2.3 ms    [User: 884.8 ms, System: 42.1 ms]
  Range (min … max):   925.2 ms … 933.2 ms    10 runs

Benchmark 2: zig-out/bin/ghostty-bench +codepoint-width --data=data.txt --mode=uucode
  Time (mean ± σ):     924.1 ms ±   0.9 ms    [User: 879.0 ms, System: 43.3 ms]
  Range (min … max):   922.8 ms … 925.4 ms    10 runs

Summary
  zig-out/bin/ghostty-bench +codepoint-width --data=data.txt --mode=uucode ran
    1.01 ± 0.00 times faster than zig-out/bin/ghostty-bench +codepoint-width --data=data.txt --mode=table
```

Arabic

```
hyperfine --warmup 1 --runs=5 zig-out/bin/ghostty-bench +codepoint-width --data=arwiki-20180920-corpus.xml --mode=table zig-out/bin/ghostty-bench +codepoint-width --data=arwiki-20180920-corpus.xml --mode=uucode
Benchmark 1: zig-out/bin/ghostty-bench +codepoint-width --data=arwiki-20180920-corpus.xml --mode=table
  Time (mean ± σ):      2.652 s ±  0.021 s    [User: 2.458 s, System: 0.180 s]
  Range (min … max):    2.622 s …  2.677 s    5 runs

Benchmark 2: zig-out/bin/ghostty-bench +codepoint-width --data=arwiki-20180920-corpus.xml --mode=uucode
  Time (mean ± σ):      2.589 s ±  0.008 s    [User: 2.405 s, System: 0.181 s]
  Range (min … max):    2.583 s …  2.598 s    5 runs

Summary
  zig-out/bin/ghostty-bench +codepoint-width --data=arwiki-20180920-corpus.xml --mode=uucode ran
    1.02 ± 0.01 times faster than zig-out/bin/ghostty-bench +codepoint-width --data=arwiki-20180920-corpus.xml --mode=table
```

Japanese

```
hyperfine --warmup 1 --runs=5 zig-out/bin/ghostty-bench +codepoint-width --data=jawiki-20181001-corpus.xml --mode=table zig-out/bin/ghostty-bench +codepoint-width --data=jawiki-20181001-corpus.xml --mode=uucode
Benchmark 1: zig-out/bin/ghostty-bench +codepoint-width --data=jawiki-20181001-corpus.xml --mode=table
  Time (mean ± σ):      2.302 s ±  0.001 s    [User: 2.126 s, System: 0.173 s]
  Range (min … max):    2.301 s …  2.303 s    5 runs

Benchmark 2: zig-out/bin/ghostty-bench +codepoint-width --data=jawiki-20181001-corpus.xml --mode=uucode
  Time (mean ± σ):      2.250 s ±  0.002 s    [User: 2.074 s, System: 0.174 s]
  Range (min … max):    2.246 s …  2.251 s    5 runs

Summary
  zig-out/bin/ghostty-bench +codepoint-width --data=jawiki-20181001-corpus.xml --mode=uucode ran
    1.02 ± 0.00 times faster than zig-out/bin/ghostty-bench +codepoint-width --data=jawiki-20181001-corpus.xml --mode=table
```

English

```
hyperfine --warmup 1 --runs=5 zig-out/bin/ghostty-bench +codepoint-width --data=enwiki-20181001-corpus.xml --mode=table zig-out/bin/ghostty-bench +codepoint-width --data=enwiki-20181001-corpus.xml --mode=uucode
Benchmark 1: zig-out/bin/ghostty-bench +codepoint-width --data=enwiki-20181001-corpus.xml --mode=table
  Time (mean ± σ):      1.770 s ±  0.005 s    [User: 1.600 s, System: 0.168 s]
  Range (min … max):    1.766 s …  1.776 s    5 runs

Benchmark 2: zig-out/bin/ghostty-bench +codepoint-width --data=enwiki-20181001-corpus.xml --mode=uucode
  Time (mean ± σ):      1.770 s ±  0.005 s    [User: 1.598 s, System: 0.169 s]
  Range (min … max):    1.765 s …  1.775 s    5 runs

Summary
  zig-out/bin/ghostty-bench +codepoint-width --data=enwiki-20181001-corpus.xml --mode=uucode ran
    1.00 ± 0.00 times faster than zig-out/bin/ghostty-bench +codepoint-width --data=enwiki-20181001-corpus.xml --mode=table
```

### grapheme-break

data.txt

```
hyperfine --warmup 4 --runs=10 zig-out/bin/ghostty-bench +grapheme-break --data=data.txt --mode=table zig-out/bin/ghostty-bench +grapheme-break --data=data.txt --mode=uucode
Benchmark 1: zig-out/bin/ghostty-bench +grapheme-break --data=data.txt --mode=table
  Time (mean ± σ):     974.5 ms ±   1.2 ms    [User: 929.2 ms, System: 43.3 ms]
  Range (min … max):   972.7 ms … 976.8 ms    10 runs

Benchmark 2: zig-out/bin/ghostty-bench +grapheme-break --data=data.txt --mode=uucode
  Time (mean ± σ):     977.4 ms ±   0.7 ms    [User: 931.5 ms, System: 44.0 ms]
  Range (min … max):   976.4 ms … 978.5 ms    10 runs

Summary
  zig-out/bin/ghostty-bench +grapheme-break --data=data.txt --mode=table ran
    1.00 ± 0.00 times faster than zig-out/bin/ghostty-bench +grapheme-break --data=data.txt --mode=uucode
```

Arabic

```
hyperfine --warmup 1 --runs=5 zig-out/bin/ghostty-bench +grapheme-break --data=arwiki-20180920-corpus.xml --mode=table zig-out/bin/ghostty-bench +grapheme-break --data=arwiki-20180920-corpus.xml --mode=uucode
Benchmark 1: zig-out/bin/ghostty-bench +grapheme-break --data=arwiki-20180920-corpus.xml --mode=table
  Time (mean ± σ):      4.135 s ±  0.022 s    [User: 3.942 s, System: 0.186 s]
  Range (min … max):    4.111 s …  4.159 s    5 runs

Benchmark 2: zig-out/bin/ghostty-bench +grapheme-break --data=arwiki-20180920-corpus.xml --mode=uucode
  Time (mean ± σ):      4.037 s ±  0.009 s    [User: 3.867 s, System: 0.163 s]
  Range (min … max):    4.026 s …  4.048 s    5 runs

Summary
  zig-out/bin/ghostty-bench +grapheme-break --data=arwiki-20180920-corpus.xml --mode=uucode ran
    1.02 ± 0.01 times faster than zig-out/bin/ghostty-bench +grapheme-break --data=arwiki-20180920-corpus.xml --mode=table
```

Japanese

```
hyperfine --warmup 1 --runs=5 zig-out/bin/ghostty-bench +grapheme-break --data=jawiki-20181001-corpus.xml --mode=table zig-out/bin/ghostty-bench +grapheme-break --data=jawiki-20181001-corpus.xml --mode=uucode
Benchmark 1: zig-out/bin/ghostty-bench +grapheme-break --data=jawiki-20181001-corpus.xml --mode=table
  Time (mean ± σ):      3.537 s ±  0.003 s    [User: 3.337 s, System: 0.195 s]
  Range (min … max):    3.533 s …  3.541 s    5 runs

Benchmark 2: zig-out/bin/ghostty-bench +grapheme-break --data=jawiki-20181001-corpus.xml --mode=uucode
  Time (mean ± σ):      3.459 s ±  0.001 s    [User: 3.265 s, System: 0.191 s]
  Range (min … max):    3.458 s …  3.460 s    5 runs

Summary
  zig-out/bin/ghostty-bench +grapheme-break --data=jawiki-20181001-corpus.xml --mode=uucode ran
    1.02 ± 0.00 times faster than zig-out/bin/ghostty-bench +grapheme-break --data=jawiki-20181001-corpus.xml --mode=table
```

English

```
hyperfine --warmup 1 --runs=5 zig-out/bin/ghostty-bench +grapheme-break --data=enwiki-20181001-corpus.xml --mode=table zig-out/bin/ghostty-bench +grapheme-break --data=enwiki-20181001-corpus.xml --mode=uucode
Benchmark 1: zig-out/bin/ghostty-bench +grapheme-break --data=enwiki-20181001-corpus.xml --mode=table
  Time (mean ± σ):      4.799 s ±  0.004 s    [User: 4.587 s, System: 0.207 s]
  Range (min … max):    4.795 s …  4.807 s    5 runs

Benchmark 2: zig-out/bin/ghostty-bench +grapheme-break --data=enwiki-20181001-corpus.xml --mode=uucode
  Time (mean ± σ):      5.119 s ±  0.002 s    [User: 4.907 s, System: 0.208 s]
  Range (min … max):    5.116 s …  5.121 s    5 runs

Summary
  zig-out/bin/ghostty-bench +grapheme-break --data=enwiki-20181001-corpus.xml --mode=table ran
    1.07 ± 0.00 times faster than zig-out/bin/ghostty-bench +grapheme-break --data=enwiki-20181001-corpus.xml --mode=uucode
```

### is-symbol

data.txt

```
hyperfine --warmup 4 --runs=10 zig-out/bin/ghostty-bench +is-symbol --data=data.txt --mode=table zig-out/bin/ghostty-bench +is-symbol --data=data.txt --mode=uucode
Benchmark 1: zig-out/bin/ghostty-bench +is-symbol --data=data.txt --mode=table
  Time (mean ± σ):     877.9 ms ±   2.0 ms    [User: 832.2 ms, System: 43.8 ms]
  Range (min … max):   873.8 ms … 881.2 ms    10 runs

Benchmark 2: zig-out/bin/ghostty-bench +is-symbol --data=data.txt --mode=uucode
  Time (mean ± σ):     883.5 ms ±   1.5 ms    [User: 837.8 ms, System: 43.8 ms]
  Range (min … max):   881.9 ms … 886.8 ms    10 runs

Summary
  zig-out/bin/ghostty-bench +is-symbol --data=data.txt --mode=table ran
    1.01 ± 0.00 times faster than zig-out/bin/ghostty-bench +is-symbol --data=data.txt --mode=uucode
```

Arabic

```
hyperfine --warmup 1 --runs=5 zig-out/bin/ghostty-bench +is-symbol --data=arwiki-20180920-corpus.xml --mode=table zig-out/bin/ghostty-bench +is-symbol --data=arwiki-20180920-corpus.xml --mode=uucode
Benchmark 1: zig-out/bin/ghostty-bench +is-symbol --data=arwiki-20180920-corpus.xml --mode=table
  Time (mean ± σ):      2.735 s ±  0.008 s    [User: 2.548 s, System: 0.183 s]
  Range (min … max):    2.724 s …  2.743 s    5 runs

Benchmark 2: zig-out/bin/ghostty-bench +is-symbol --data=arwiki-20180920-corpus.xml --mode=uucode
  Time (mean ± σ):      2.611 s ±  0.001 s    [User: 2.427 s, System: 0.181 s]
  Range (min … max):    2.610 s …  2.612 s    5 runs

Summary
  zig-out/bin/ghostty-bench +is-symbol --data=arwiki-20180920-corpus.xml --mode=uucode ran
    1.05 ± 0.00 times faster than zig-out/bin/ghostty-bench +is-symbol --data=arwiki-20180920-corpus.xml --mode=table
```

Japanese

```
hyperfine --warmup 1 --runs=5 zig-out/bin/ghostty-bench +is-symbol --data=jawiki-20181001-corpus.xml --mode=table zig-out/bin/ghostty-bench +is-symbol --data=jawiki-20181001-corpus.xml --mode=uucode
Benchmark 1: zig-out/bin/ghostty-bench +is-symbol --data=jawiki-20181001-corpus.xml --mode=table
  Time (mean ± σ):      2.391 s ±  0.002 s    [User: 2.210 s, System: 0.178 s]
  Range (min … max):    2.387 s …  2.393 s    5 runs

Benchmark 2: zig-out/bin/ghostty-bench +is-symbol --data=jawiki-20181001-corpus.xml --mode=uucode
  Time (mean ± σ):      2.276 s ±  0.004 s    [User: 2.100 s, System: 0.173 s]
  Range (min … max):    2.274 s …  2.283 s    5 runs

Summary
  zig-out/bin/ghostty-bench +is-symbol --data=jawiki-20181001-corpus.xml --mode=uucode ran
    1.05 ± 0.00 times faster than zig-out/bin/ghostty-bench +is-symbol --data=jawiki-20181001-corpus.xml --mode=table
```

English

```
hyperfine --warmup 1 --runs=5 zig-out/bin/ghostty-bench +is-symbol --data=enwiki-20181001-corpus.xml --mode=table zig-out/bin/ghostty-bench +is-symbol --data=enwiki-20181001-corpus.xml --mode=uucode
Benchmark 1: zig-out/bin/ghostty-bench +is-symbol --data=enwiki-20181001-corpus.xml --mode=table
  Time (mean ± σ):      2.450 s ±  0.005 s    [User: 2.267 s, System: 0.179 s]
  Range (min … max):    2.446 s …  2.457 s    5 runs

Benchmark 2: zig-out/bin/ghostty-bench +is-symbol --data=enwiki-20181001-corpus.xml --mode=uucode
  Time (mean ± σ):      2.212 s ±  0.002 s    [User: 2.036 s, System: 0.173 s]
  Range (min … max):    2.208 s …  2.214 s    5 runs

Summary
  zig-out/bin/ghostty-bench +is-symbol --data=enwiki-20181001-corpus.xml --mode=uucode ran
    1.11 ± 0.00 times faster than zig-out/bin/ghostty-bench +is-symbol --data=enwiki-20181001-corpus.xml --mode=table
```
2025-09-30 06:54:17 -07:00
Mitchell Hashimoto
d261c0a60b Merge branch 'main' into jacob/uucode 2025-09-30 06:52:07 -07:00
Mitchell Hashimoto
449386001b gtk: some bell features need to happen on receipt of every BEL (#8962)
Some bell features should be triggered on the receipt of every BEL
character, namely `audio` and `system`. However, Ghostty was setting a
boolean to `true` upon the receipt of the first BEL. Subsequent BEL
characters would be ignored until that boolean was reset to `false`,
usually by keyboard/mouse activity.

This PR fixes the problem by ensuring that the `audio` and `system`
features are triggered every time a BEL is received. Other features
continue to be triggered only when the `bell-ringing` boolean state
changes.

Fixes #8957
2025-09-30 06:44:41 -07:00
Jeffrey C. Ollie
bdf07727ad gtk: some bell features need to happen on receipt of every BEL
Some bell features should be triggered on the receipt of every BEL
character, namely `audio` and `system`. However, Ghostty was setting a
boolean to `true` upon the receipt of the first BEL. Subsequent BEL
characters would be ignored until that boolean was reset to `false`,
usually by keyboard/mouse activity.

This PR fixes the problem by ensuring that the `audio` and `system`
features are triggered every time a BEL is received. Other features
continue to be triggered only when the `bell-ringing` boolean state
changes.

Fixes #8957
2025-09-30 06:40:34 -07:00
himura467
c58a8b27b6 chore: update iOS membership exceptions 2025-09-30 07:14:09 +09:00
himura467
373be61482 docs 2025-09-30 06:36:29 +09:00
himura467
b3d0b6a965 refactor: no need to set from for moveFocus probably 2025-09-30 05:58:21 +09:00
himura467
bc3d0b7cbc fix: the renderer's cursor remains in an unfocused state (block_hollow) 2025-09-30 05:21:56 +09:00
Mitchell Hashimoto
7ba9f9a21a gtk: make Enter confirm "Change Terminal Title" (#8949)
Fixes https://github.com/ghostty-org/ghostty/discussions/8697 by making
`OK` the suggested default and activating it by default.

Previously `OK` was `destructive` which imo is not a good approach for
just setting a terminal title.
2025-09-29 12:35:05 -07:00
Mitchell Hashimoto
0bddaed53b fix(font): Improve FreeType glyph measurements and add unit tests for face metrics (#8738)
Follow-up to #8720 adding

* Two improvements to FreeType glyph measurements:
- Ensuring that glyphs are measured with the same hinting as they are
rendered, ref
[#8720#issuecomment-3305408157](https://github.com/ghostty-org/ghostty/pull/8720#issuecomment-3305408157);
- For outline glyphs, using the outline bbox instead of the built-in
metrics, like `renderGlyph()`.
* Basic unit tests for face metrics and their estimators, using the
narrowest and widest fonts from the resource directory, Cozette Vector
and Geist Mono.

---

I also made one unrelated change to `freetype.zig`, replacing
`@alignCast(@ptrCast(...))` with `@ptrCast(@alignCast(...))` on line
173. Autoformatting has been making this change on every save for weeks,
and reverting the hunk before each commit is getting old, so I hope it's
OK that I use this PR to upstream this decree from the formatter.
2025-09-29 12:24:42 -07:00
Mitchell Hashimoto
b643d30d60 move test out of terminal to avoid lib-vt catch 2025-09-29 12:24:04 -07:00
Mitchell Hashimoto
f67a865cdd fix(font): Treat Powerline glyphs as normal characters for constraint width purposes (#8829)
Powerline glyphs were treated as whitespace, giving the preceding cell a
constraint width of 2 and cutting off icons in people's prompts and
statuslines. It is however correct to not treat Powerline glyphs like
other Nerd Font symbols; they should simply be treated as normal
characters, just like their relatives in the block elements unicode
block.

This resolves
https://discord.com/channels/1005603569187160125/1417236683266592798
(never promoted to an issue, but real and easy to reproduce).

**Tip**
<img width="215" height="63" alt="Screenshot 2025-09-21 at 16 57 58"
src="https://github.com/user-attachments/assets/81e770c5-d688-4d8e-839c-1f4288703c06"
/>

**This PR**
<img width="215" height="63" alt="Screenshot 2025-09-21 at 16 58 42"
src="https://github.com/user-attachments/assets/5d2dd770-0314-46f6-99b5-237a0933998e"
/>

The constraint width logic was untested but contains some quite subtle
interactions, so I wrote a suite of tests covering the cases I'm aware
of.

While working on this code I also resolved a TODO comment to add all the
box drawing/block element type characters to the set of codepoints
excluded from the minimum contrast settings.
2025-09-29 12:16:23 -07:00
Mitchell Hashimoto
25dab0ecd8 fix(font): Rewrite constraint code for improved icon scaling/alignment (#8563)
> This PR will probably need a rebase on the final outcome of #8550 and
~#8552~ #8580, but I'm putting it out here so folks can begin taking a
look if they want.

This is a rewrite of the code that applies scaling and alignment
constraints. The main intention is to further improve how Nerd Font
icons are matched to the primary font. This PR aligns the calculations
more closely with how the Nerd Font `font-patcher` script works, except
in two cases where we can easily do something unambiguously better (one
because of what's arguably a bug in the script, and one because we do
multi-cell alignment with knowledge of the pixel-rounded cell grid).

A goal of the rewrite is to make the scaling and alignment calculations
as clear and easy to follow as possible.

I'll lead with some screenshots. First the status quo, then this PR.
<img width="505" height="357" alt="Screenshot 2025-09-07 at 17 23 51"
src="https://github.com/user-attachments/assets/8e3ff9fd-3b66-4d54-be38-d54cf3b6cc5b"
/><img width="505" height="357" alt="Screenshot 2025-09-07 at 17 20 39"
src="https://github.com/user-attachments/assets/84fbe076-2e3f-4879-b9b2-91ce86b9ef5f"
/>

Relevant specs: macOS; 1920x1080; Ghostty config:
```ini
font-family = "CommitMono"
font-size = "15"
adjust-cell-height = "+20%"
```

**Points to note**

* Icons are generally larger, making better use of the available space.
* Icons are aligned nearly a pixel lower, better matching the text. This
is because alignment is now calculated from face metrics/bearings, not
the pixel-rounded cell. (See more below.)
* Relative sizes are better matched. Note especially that tall and
narrow icons, like the git branch symbol and icons depicting sheets of
paper, look conspicuously small in the status quo. With this PR, they're
better matched to other icons.
* Look at the letter Z icon I use as prompt character for zsh. It's
_tiny_ in the status quo, but properly sized with this PR. This
demonstrates the most important and clear-cut improvement we make over
`font-patcher`. (See more below.)
* Icons wider than a single cell are now left-aligned rather than
centered across two cells. I think this is preferable and makes better
use of space in most relevant contexts.
- Consider a Neovim bufferline showing the buffer title as a filetype
icon followed by the file name. Padding on the left would be a waste of
space, but having that extra space on the right can improve legibility.
- In listings, such as in the screenshots, columns look tidier when
their left edges are straight rather than ragged.
- This is how `font-patcher` does alignment, and thus what Nerd Font
users and UI designers expect.

**Implementation details**

I won't get too deep in the weeds here; see the code and comments. In
brief:

* `size_horizontal` and `size_vertical` are combined to a single `size`,
which can be `.none, .stretch, .fit, .cover` or `.fit_cover1`. The
latter implements the `pa` rule from `font-patcher`, except it works
better for icons that are small before scaling, like the letter Z prompt
in the screenshots. In short, it preserves aspect ratio while clamping
the size such that the icon `.cover`s at least one cell and `.fit`s
within the available space. See code comments and
ryanoasis/nerd-fonts/pull/1926 for details.
* An alignment mode `.center1` is added, implementing the centering rule
from `font-patcher` that I explained/defended above. In short, we center
the icon _in the first cell_, even it's allowed to span multiple cells.
For icons wider than a single cell, the lower bound that prevents them
from protruding to the left kicks in and turns this into left-alignment.
We keep the regular `.center` rule around for use with emojis, et
cetera.
* Scaling and alignment calculations only use the unrounded face metrics
and bearings. This ensures that pixel rounding of the cell and baseline,
and `adjust-cell-{width,height}`, don't affect scaling or relative
alignment; the icons are always scaled and aligned to the _face_. (The
one place we need to use cell metrics in the calculations is when we use
`cell_width` to obtain the inter-cell padding needed to correctly center
or right-align a glyph across two cells.)
- We can do this with impunity because we're blessed with sprite glyphs
in place of the "icons" that are actually box drawing and block graphics
characters 🙌

**Guide**

The meat of the changes is 100 % in `src/font/face.zig` and
`src/font/nerd_font_codegen.py`. Changes to other files only amount to
a) adding/changing some struct fields to get numbers to where they need
to be (see `src/font/Metrics.zig`), and b) collateral updates to make
otherwise unchanged code and tests work with/take advantage of the
modified structs.

Most files should have a clear and friendly diff. The exception is the
bottom half of `src/font/face.zig`, where the diff is meaningless and
the new code should just be reviewed on its own merits. This is the part
where the `constrain` function is rewritten and refactored. Scarred by
countless hours perusing `font-patcher`, I tried hard to make the math
and logic easy to follow here. I hope I have succeeded 🤞
2025-09-29 12:12:09 -07:00
Daniel Wennberg
e3ebdc7975 Rewrite constraint code for improved icon scaling/alignment 2025-09-29 12:09:21 -07:00
Mitchell Hashimoto
f73666a7a1 apprt/gtk: do not close window if tab overview is open with no tabs (#8955)
Fixes #8944

When we drag the only tab out of the tab overview, this triggers an
`n-pages` signal with 0 pages. If we close the window in this state, it
causes both Ghostty to exit AND the drag/drop to fail. Even if we
pre-empt Ghostty exiting by modifying the application class, the
drag/drop still fails and the application leaks memory and enters a bad
state.

The solution is to keep the window open if we go to `n-pages == 0` and
we have the tab overview open.

Interestingly, if you click to close the final tab from the tab
overview, Adwaita closes the tab overview so it still triggers the
window closing behavior (this is good, this is desired).
2025-09-29 10:53:56 -07:00
Mitchell Hashimoto
3fdb52e48d apprt/gtk: do not close window if tab overview is open with no tabs
Fixes #8944

When we drag the only tab out of the tab overview, this triggers
an `n-pages` signal with 0 pages. If we close the window in this state,
it causes both Ghostty to exit AND the drag/drop to fail. Even if we
pre-empt Ghostty exiting by modifying the application class, the
drag/drop still fails and the application leaks memory and enters a bad
state.

The solution is to keep the window open if we go to `n-pages == 0` and
we have the tab overview open.

Interestingly, if you click to close the final tab from the tab
overview, Adwaita closes the tab overview so it still triggers the
window closing behavior (this is good).
2025-09-29 10:48:22 -07:00
Mitchell Hashimoto
a2663692bb feat: enable scaling mouse-scroll-multiplier for both precision and discrete scrolling (#8927)
Resolves Issue: #8670 

Now precision and discrete scrolling can be scaled independently.
Supports following configuration,

```code
# Apply everywhere
mouse-scroll-multiplier = 3

# Apply separately
mouse-scroll-multiplier = precision:0.1,discrete:3 (default)

# Also it's order agnostic
mouse-scroll-multiplier = discrete:3,precision:2

# Apply one, default other
mouse-scroll-multiplier = precision:2
```

The default precision value is set 0.1, as it felt natural to me at
least on my track-pad. I've also set the min clamp value precision to
0.1 as 0.01 felt kind of useless to me but I'm unsure.
2025-09-29 10:21:36 -07:00
Mitchell Hashimoto
1031629741 config: modify MouseScrollMultiplier to lean on args parsing 2025-09-29 10:08:58 -07:00
Toufiq Shishir
9597cead92 add: unit tests for MouseScrollMultiplier parsing and formatting 2025-09-29 09:30:55 -07:00
Toufiq Shishir
33e0701965 feat: enable separate scaling for precision and discrete mouse scrolling 2025-09-29 09:30:55 -07:00
Mitchell Hashimoto
958751e12c Workaround for #8669 (#8838)
Changing `supportedModes` to `background` seems to have fixed #8669.

> Debugging AppIntents with Xcode is a pain. I had to delete all the
local builds to make it take effect. The build product of `zig` might
cause confusion if none of your changes reflect in the Shortcuts app.
There were too many ghosts on my computer. 👻👻👻

- Tahoe


https://github.com/user-attachments/assets/88d0d567-edf5-4a7e-b0a3-720e50053746

- Sequoia 


https://github.com/user-attachments/assets/a77f1431-ca92-4450-bce9-5f37ef232d4f
2025-09-29 09:30:01 -07:00
Mitchell Hashimoto
9ba45b2163 lib-vt: fix invalid Zig forwards 2025-09-29 09:18:43 -07:00
Mitchell Hashimoto
cc0b7f74fd lib-vt: document allocators 2025-09-29 09:12:12 -07:00
Mitchell Hashimoto
15670a77f3 lib-vt: document main html page 2025-09-29 08:59:16 -07:00
Mitchell Hashimoto
16077f0542 build: move entrypoint out to separate file 2025-09-29 08:51:56 -07:00
Mitchell Hashimoto
904e09a1da build: add NOINDEX argument for libghostty-vt docs 2025-09-29 08:48:07 -07:00
Mitchell Hashimoto
3a95920edf build: add Dockerfile to generate and server libghostty c docs 2025-09-29 08:33:58 -07:00
Mitchell Hashimoto
12d3c130c8 lib-vt: OSC data extraction boilerplate (#8950)
This adds functions to extra data out of OSC commands, but it is mostly
boilerplate since I only added one valid data extraction. 😄 The example
was updated to show this.

This also changes OSC strings to be null-terminated to ease lib-vt
integration. This shouldn't have any practical effect on terminal
performance, but it does lower the maximum length of OSC strings by 1
since we always reserve space for the null terminator.
2025-09-29 06:56:07 -07:00
Mitchell Hashimoto
3bc07c24aa lib-vt: OSC data extraction boilerplate
This also changes OSC strings to be null-terminated to ease lib-vt
integration. This shouldn't have any practical effect on terminal
performance, but it does lower the maximum length of OSC strings by 1
since we always reserve space for the null terminator.
2025-09-29 06:40:01 -07:00
Bernd Kaiser
41c1c6b3e6 gtk: make Enter confirm "Change Terminal Title" 2025-09-29 14:44:20 +02:00
Mitchell Hashimoto
c5145d552e build: use build options to configure terminal C ABI mode (#8945)
Fixes various issues:

- C ABI detection was faulty, which caused some Zig programs to use the
C ABI mode and some C programs not to. Let's be explicit.

- Unit tests now tests C ABI mode.

- Build binary no longer rebuilds on any terminal change (a regression).

- Zig programs can choose to depend on the C ABI version of the terminal
lib by using the `ghostty-vt-c` module.
2025-09-28 14:22:36 -07:00
Mitchell Hashimoto
f614fb7c1b build: use build options to configure terminal C ABI mode
Fixes various issues:

- C ABI detection was faulty, which caused some Zig programs to use
the C ABI mode and some C programs not to. Let's be explicit.

- Unit tests now tests C ABI mode.

- Build binary no longer rebuilds on any terminal change (a regression).

- Zig programs can choose to depend on the C ABI version of the terminal
  lib by using the `ghostty-vt-c` module.
2025-09-28 14:17:51 -07:00
Mitchell Hashimoto
08ecbe328a Update iTerm2 colorschemes (#8933)
Upstream release:
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/tag/release-20250922-150534-d28055b
2025-09-28 13:37:38 -07:00
Mitchell Hashimoto
b73fdd4326 lib-vt C: More OSC parsing API (#8941)
This adds more of the OSC parsing API to the C library of
`libghostty-vt`. This adds the following:

* `ghostty_osc_next` - Push a single character into the OSC parser
* `ghostty_osc_reset` - Reset the parser state and free any temporary
memory
* `ghostty_osc_end` - End a parsing sequence and return the parsed
command
* `ghostty_osc_command_type` - Return the type of command parsed
* `examples/c-vt` is updated to use these new APIs
* Our Zig `osc.Command` tagged union is updated to use a new comptime
func to generate an ABI compatible tag for the C lib.
* **Important change:** Our Zig `osc.Parser.end` function was modified
to return a _pointer_ to the command within its own structure memory
rather than a copy. This eases the C API. This impacts the Zig side but
we ultimately copy it again [for now] in the main `terminal.Parser` so
end result is the same.
* Unit tests cover even the C lib
* Shuffled some code for maintainability

The plan is to use this opaque type with getters to ease ABI
compatibility going forward.
2025-09-28 13:37:23 -07:00
himura467
a6dd7bbeee refactor: improve asynchronous delay by delegating window/app activation process to animateIn 2025-09-29 02:02:42 +09:00
himura467
7ab0a7814b docs(BaseTerminalController) 2025-09-29 01:56:00 +09:00
himura467
337ecdd0b3 refactor(focusSurface): check app status in advance 2025-09-29 00:02:43 +09:00
himura467
8151f4bbf5 feat: focusSurface for quick terminal 2025-09-29 00:00:41 +09:00
Mitchell Hashimoto
a76297058f example/c-vt: parse a full OSC command 2025-09-28 07:24:09 -07:00
Mitchell Hashimoto
cfe9f19454 lib-vt: expose command type enum 2025-09-28 07:21:46 -07:00
himura467
9d33545a55 feat: focus terminal in basic cases 2025-09-28 19:20:00 +09:00
mitchellh
89fc7139ae deps: Update iTerm2 color schemes 2025-09-28 00:15:36 +00:00
Mitchell Hashimoto
f564ffa30b lib-vt: expose ghostty_osc_end 2025-09-27 15:15:51 -07:00
Mitchell Hashimoto
cc0f2e79cd terminal: osc parser end returns a pointer 2025-09-27 15:07:56 -07:00
Mitchell Hashimoto
6b1f4088dd lib-vt: add the C functions for command inspection 2025-09-27 15:03:38 -07:00
Mitchell Hashimoto
6a0a94c827 lib: fix holes handling for C 2025-09-27 14:43:01 -07:00
Mitchell Hashimoto
397e47c274 terminal: use LibEnum for the command keys 2025-09-27 14:32:49 -07:00
Mitchell Hashimoto
a79e68ace1 lib: enum func 2025-09-27 14:25:06 -07:00
Mitchell Hashimoto
b3d1802c89 lib_vt: osc_next/reset 2025-09-27 13:25:56 -07:00
Mitchell Hashimoto
8a1dc5bd97 terminal: shuffle some C APIs to make it more long term maintainable 2025-09-27 13:20:54 -07:00
Mitchell Hashimoto
e4e8a61e0c build: limit cpu affinity to 32 cpus on Linux (#8925)
Related to #8924

Zig currenly has a bug where it crashes when compiling Ghostty on
systems with more than 32 cpus (See the linked issue for the gory
details). As a temporary hack, use `sched_setaffinity` on Linux systems
to limit the compile to the first 32 cores. Note that this affects the
build only. The resulting Ghostty executable is not limited in any way.

This is a more general fix than wrapping the Zig compiler with
`taskset`. First of all, it requires no action from the user or
packagers. Second, it will be easier for us to remove once the upstream
Zig bug is fixed.
2025-09-27 12:34:57 -07:00
Jeffrey C. Ollie
311f8ec70b build: limit cpu affinity to 32 cpus on Linux
Related to #8924

Zig currenly has a bug where it crashes when compiling Ghostty on
systems with more than 32 cpus (See the linked issue for the gory
details). As a temporary hack, use `sched_setaffinity` on Linux systems
to limit the compile to the first 32 cores. Note that this affects the
build only. The resulting Ghostty executable is not limited in any way.

This is a more general fix than wrapping the Zig compiler with
`taskset`. First of all, it requires no action from the user or
packagers. Second, it will be easier for us to remove once the upstream
Zig bug is fixed.
2025-09-27 12:29:39 -07:00
Mitchell Hashimoto
7749b46463 chore: pin zig 0.14 in build.zig.zon (#8871)
Hi!

I'm a full Zig noob but [Mitchell's recent
post](https://mitchellh.com/writing/libghostty-is-coming) made me want
to clone the repo and take a look at the tooling.

My first attempt at running examples though VSCode failed because the
latest version of Zig is 0.15.1, but Ghostty requires Zig 0.14*. When
configuring the extension to use a compatible version if Zig, it
suggested pinning the version in a .zigversion file. I'm not familiar
with the pattern, but if it can help someone else's onboarding, I
figured I'd open a PR to suggest the change.

Cheers

*edit: I had a hard time figuring that out
2025-09-26 06:58:44 -07:00
Mitchell Hashimoto
6995fd7f10 fix: alloc free off by one (#8886)
Fix provided by @jcollie 

The swift `open_config` action was triggering an allocation error
`error(gpa): Allocation size 41 bytes does not match free size 40.`.

> A string that was created as a `[:0]const u8` was cast to `[]const u8`
and then freed. The sentinel is the off-by-one.

@jcollie 

For full context, see
https://discord.com/channels/1005603569187160125/1420367156071239820

Co-authored-by: Jeffrey C. Ollie <jcollie@dmacc.edu>
2025-09-26 06:58:10 -07:00
Mitchell Hashimoto
7975316ceb vim: use :setf to set the filetype (#8914)
This is nicer because it only sets the filetype if it hasn't already
been set. :setf[iletype] has been available since vim version 6.

See: https://vimhelp.org/options.txt.html#%3Asetf
2025-09-26 06:57:28 -07:00
Mitchell Hashimoto
d9080cd83c build(deps): bump namespacelabs/nscloud-cache-action from 1.2.17 to 1.2.18 (#8916)
Bumps
[namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action)
from 1.2.17 to 1.2.18.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="7baedde84b"><code>7baedde</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/36">#36</a>
from namespacelabs/niklas-docs</li>
<li><a
href="72a48b9085"><code>72a48b9</code></a>
fix docs links</li>
<li><a
href="f5a0d9e059"><code>f5a0d9e</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/35">#35</a>
from namespacelabs/niklas-workflow</li>
<li><a
href="7bb48a0f26"><code>7bb48a0</code></a>
skip bundle exec</li>
<li><a
href="32d69b87dc"><code>32d69b8</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/34">#34</a>
from namespacelabs/niklas-apple-caches</li>
<li><a
href="a49d9d84e9"><code>a49d9d8</code></a>
Add experimental cache modes for Xcode, Swift, Ruby and CocoaPods</li>
<li>See full diff in <a
href="a289cf5d2f...7baedde84b">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=namespacelabs/nscloud-cache-action&package-manager=github_actions&previous-version=1.2.17&new-version=1.2.18)](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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-25 17:12:19 -07:00
dependabot[bot]
fdbf0c6242 build(deps): bump namespacelabs/nscloud-cache-action
Bumps [namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action) from 1.2.17 to 1.2.18.
- [Release notes](https://github.com/namespacelabs/nscloud-cache-action/releases)
- [Commits](a289cf5d2f...7baedde84b)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-26 00:06:22 +00:00
Jon Parise
79a5902ef2 vim: use :setf to set the filetype
This is nicer because it only sets the filetype if it hasn't already
been set. :setf[iletype] has been available since vim version 6.

See: https://vimhelp.org/options.txt.html#%3Asetf
2025-09-25 16:39:11 -04:00
CoderJoshDK
d79441edd1 test: valid string slices for ghostty_string_s 2025-09-25 12:26:52 -04:00
Jacob Sandlund
1d89a63f29 Use commit pointed to by signed tag v0.1.0-zig-0.14 2025-09-25 10:00:03 -04:00
Jacob Sandlund
beda36a3ca Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-25 09:59:51 -04:00
Mitchell Hashimoto
230014a536 cli: use sh to launch editor (#8901)
Fixes #8898
2025-09-25 06:52:58 -07:00
Jacob Sandlund
76cafeb957 move ziglyph dep to SharedDeps with .@"test" condition 2025-09-25 08:48:19 -04:00
Jacob Sandlund
4f2d80b08f Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-25 08:43:18 -04:00
Filip Milković
f8fa812932 i18n: add Croatian hr_HR translation (#8668) 2025-09-25 09:45:41 +00:00
Gautier Ben Aïm
22cf46aefc use 0.14.1 2025-09-25 09:08:57 +02:00
Mitchell Hashimoto
dbbff53af7 build(deps): bump cachix/install-nix-action from 31.6.2 to 31.7.0 (#8904)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.6.2 to 31.7.0.
<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.7.0</h2>
<h2>What's Changed</h2>
<ul>
<li>
<p>feat: set up the environment based on the installer shell scripts by
<a href="https://github.com/sandydoo"><code>@​sandydoo</code></a> in <a
href="https://redirect.github.com/cachix/install-nix-action/pull/251">cachix/install-nix-action#251</a></p>
<p>Configures the following environment variables:</p>
<ul>
<li><code>NIX_PROFILES</code></li>
<li><code>NIX_SSL_CERT_FILE</code> (if not set)</li>
</ul>
<p>Adds the bin directory from the user's profile to
<code>$PATH</code>.</p>
</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31.6.2...v31.7.0">https://github.com/cachix/install-nix-action/compare/v31.6.2...v31.7.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9280e7aca8"><code>9280e7a</code></a>
fix: use -e to check for certs</li>
<li><a
href="effa594a17"><code>effa594</code></a>
fix: simplify setting the user profile</li>
<li><a
href="eb0f6c7357"><code>eb0f6c7</code></a>
ci: document where to find available images to test against</li>
<li><a
href="6676c23a71"><code>6676c23</code></a>
ci: add ubuntu-22.04-arm</li>
<li><a
href="cbf4b16d11"><code>cbf4b16</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/251">#251</a>
from cachix/fix-env</li>
<li><a
href="29a4dac2fa"><code>29a4dac</code></a>
tests: refactor tests to run under a single matrix</li>
<li><a
href="7449e8905b"><code>7449e89</code></a>
tests: improve env tests and move to tests dir</li>
<li><a
href="d487f94a7a"><code>d487f94</code></a>
lint</li>
<li><a
href="581a134122"><code>581a134</code></a>
refactor: document ssl-cert-file vs NIX_SSL_CERT_FILE</li>
<li><a
href="d914f6d9e8"><code>d914f6d</code></a>
refactor: drop ssl handling for unsupported platforms</li>
<li>Additional commits viewable in <a
href="a809471b5c...9280e7aca8">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.6.2&new-version=31.7.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-24 20:24:38 -07:00
dependabot[bot]
74419b2fcf build(deps): bump cachix/install-nix-action from 31.6.2 to 31.7.0
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.6.2 to 31.7.0.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](a809471b5c...9280e7aca8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-25 00:08:57 +00:00
Jeffrey C. Ollie
bff758f03b cli: use sh to launch editor 2025-09-24 17:47:29 -05:00
CoderJoshDK
dc03a47558 chore: sync changes with ghostty_string_s 2025-09-24 17:47:24 -04:00
Jeffrey C. Ollie
79685f87c4 use comptime to make C String interface nicer 2025-09-24 16:33:18 -05:00
CoderJoshDK
c5786c5d38 fix: alloc free off by one 2025-09-24 16:58:39 -04:00
Mitchell Hashimoto
fc0a37f9e0 GTK: Fix split-divider-color (#8853)
The `loadRuntimeCss416` overrode a color option for the split divider
color

https://github.com/ghostty-org/ghostty/blob/main/src/apprt/gtk/class/application.zig#L959-L965

I moved the user config options until the other runtime css is loaded so
they will always take priority
2025-09-24 12:58:25 -07:00
Mitchell Hashimoto
103e7abad5 config: smarter parsing in autoParseStruct (#8873)
Fixes #8849

Previously, the `parseAutoStruct` function that was used to parse
generic structs for the config simply split the input value on commas
without taking into account quoting or escapes. This led to problems
because it was impossible to include a comma in the value of config
entries that were parsed by `parseAutoStruct`. This is particularly
problematic because `ghostty +show-config --default` would produce
output like the following:

```
command-palette-entry = title:Focus Split: Next,description:Focus the next split, if any.,action:goto_split:next
```

Because the `description` contains a comma, Ghostty is unable to parse
this correctly. The value would be split into four parts:

```
title:Focus Split: Next
description:Focus the next split
 if any.
action:goto_split:next
```

Instead of three parts:

```
title:Focus Split: Next
description:Focus the next split, if any.
action:goto_split:next
```

Because `parseAutoStruct` simply looked for commas to split on, no
amount of quoting or escaping would allow that to be parsed correctly.

This is fixed by (1) introducing a parser that will split the input to
`parseAutoStruct` into fields while taking into account quotes and
escaping. And (2) changing the `ghostty +show-config` output to put the
values in `command-palette-entry` into quotes so that Ghostty can parse
it's own output.

`parseAutoStruct` will also now parse double quoted values as a Zig
string literal. This makes it easier to embed control codes, whitespace,
and commas in values.
2025-09-24 12:54:27 -07:00
Mitchell Hashimoto
64800d94ba fix: file creation when directory already exists (#8892)
Resolves #8890 

If you try to create the config file when the directory already exists,
you (I) get an error that the _file_ path already exists.
```
warning(config): error creating template config file err=error.PathAlreadyExists
```
Even though the file does not exist. By changing the API entry point,
this error goes away.

I have no solid explanation for why this change works.


| State | Old Behavior | New Behavior |
|--------|--------|--------|
| A config file exists | N/A | N/A |
| No config file, no directory | create directory and config file | N/A
|
| No config file, yes directory | fail to create on config file | create
config file |

This behavior is confirmed on my macOS 26 machine. It is the least
intrusive change I could make, and in all other situations should be a
no-op.
2025-09-24 12:51:09 -07:00
Mitchell Hashimoto
232b1898fa lib-vt: update header comments 2025-09-24 12:50:25 -07:00
Mitchell Hashimoto
390f72accc libghostty-vt C shared library boilerplate, custom allocators API (#8895)
This adds the boilerplate necessary for `libghostty-vt` the C library.

> [!IMPORTANT]
>
> This _does not expose almost any APIs_. The point of this PR is to
setup our boilerplate, build system, docs system, etc. for the
libghostty-vt C lib.

- Adds a `zig build lib-vt` target to _only_ build `libghostty-vt`
- Adds the beginning of `include/ghostty-vt.h` for the C API 
- Adds a full custom allocator interface to the C API mimicking Zig
custom allocators
- Adds an example in `example/c-vt` that builds a pure C program and
links to our shared library and calls functions
- Adds the `osc_parser_new/free` C APIs just as a proof of concept that
things work
- Adds a basic Doxygen config so we have _something_ (I'm not at all
committed to Doxygen, but want us to doc from the beginning)
- Updates CI to test building the shared library for macOS, Windows, and
Linux (yes, it builds for Windows!)

**Note:** To use the `dep.artifact` function provided by Zig, we must
install the artifact. But this means that every `zig build` now includes
`libghostty-vt`. That... could be completely fine, but it's something to
consider for packagers.

## Bikeshed

We're at a pivotal point where we must define the general _style_ of our
C API.

This includes the very bike shed things such as capitalization styling,
but also general API form.

ABI compatibility will eventually be important.

I'm very much open and would love to receive feedback form more
experience C programmers on what they feel would constitute a good API.
I've consumed _many_ C APIs but I haven't provided many directly.

cc @gpanders
2025-09-24 12:45:34 -07:00
Mitchell Hashimoto
37372fa50b more docs 2025-09-24 12:45:21 -07:00
Mitchell Hashimoto
37e238c2f6 remove vt prefixes 2025-09-24 12:36:50 -07:00
Mitchell Hashimoto
96e9053862 move header into subdirectory 2025-09-24 12:30:37 -07:00
Mitchell Hashimoto
48827b21d8 some PR feedback 2025-09-24 12:25:43 -07:00
Mitchell Hashimoto
513cdf667b build: add pkg-config for libghostty-vt 2025-09-24 12:22:09 -07:00
Mitchell Hashimoto
0944f051aa terminal: simplify opaque type 2025-09-24 11:09:19 -07:00
Mitchell Hashimoto
4d165fbaaa remove unused items 2025-09-24 11:06:23 -07:00
Mitchell Hashimoto
43089a01f1 lib: c allocator can use fromZig 2025-09-24 11:00:48 -07:00
Mitchell Hashimoto
fba953feeb ci: run the c-vt example 2025-09-24 10:46:43 -07:00
Mitchell Hashimoto
e7a0198103 lib-vt: docs 2025-09-24 10:46:24 -07:00
Mitchell Hashimoto
2c78ad8889 lib-vt: setup a default allocator if null 2025-09-24 10:30:13 -07:00
Mitchell Hashimoto
de013148d3 build: install the ghostty-vt artifact 2025-09-24 10:17:50 -07:00
Mitchell Hashimoto
e1429dabae example/c-vt 2025-09-24 09:54:08 -07:00
Mitchell Hashimoto
969fcfaec3 lib: allocator interface based on Zig allocators 2025-09-24 09:27:17 -07:00
CoderJoshDK
315b54822a fix: file creation when directory already exists 2025-09-24 12:08:12 -04:00
Jacob Sandlund
8bcab93c21 separate out runtime and buildtime uucode tables 2025-09-24 08:34:21 -04:00
Jacob Sandlund
444b40bc4a Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-24 08:05:29 -04:00
Jeffrey C. Ollie
5f3fd9742f rename Splitter-CommaSplitter 2025-09-23 21:53:52 -05:00
Jeffrey C. Ollie
5265414a36 config: smarter parsing in autoParseStruct
Fixes #8849

Previously, the `parseAutoStruct` function that was used to parse
generic structs for the config simply split the input value on commas
without taking into account quoting or escapes. This led to problems
because it was impossible to include a comma in the value of config
entries that were parsed by `parseAutoStruct`. This is particularly
problematic because `ghostty +show-config --default` would produce
output like the following:

```
command-palette-entry = title:Focus Split: Next,description:Focus the next split, if any.,action:goto_split:next
```

Because the `description` contains a comma, Ghostty is unable to
parse this correctly. The value would be split into four parts:

```
title:Focus Split: Next
description:Focus the next split
 if any.
action:goto_split:next
```

Instead of three parts:

```
title:Focus Split: Next
description:Focus the next split, if any.
action:goto_split:next
```

Because `parseAutoStruct` simply looked for commas to split on, no
amount of quoting or escaping would allow that to be parsed correctly.

This is fixed by (1) introducing a parser that will split the input
to `parseAutoStruct` into fields while taking into account quotes and
escaping. And (2) changing the `ghostty +show-config` output to put the
values in `command-palette-entry` into quotes so that Ghostty can parse
it's own output.

`parseAutoStruct` will also now parse double quoted values as a Zig
string literal. This makes it easier to embed control codes, whitespace,
and commas in values.
2025-09-23 20:44:49 -05:00
Mitchell Hashimoto
32bf37e5e4 setup basic doxygen for docs
We may not stick with Doxygen, but it gives us something to start with.
2025-09-23 15:51:27 -07:00
Mitchell Hashimoto
def4969aff build: shared object is a dylib on macOS 2025-09-23 15:15:16 -07:00
Mitchell Hashimoto
3d04fbb451 ci: build lib-vt for a variety of targets
We don't run our tests on all these targets so its not sure they all
will function correctly, but at least we can be sure they build.
2025-09-23 15:04:24 -07:00
Mitchell Hashimoto
85345c31cf build: don't add deps when cross compiling to darwin 2025-09-23 15:03:55 -07:00
Brice
35095fddda comment to load standard css options before some of the user configured styles 2025-09-23 15:15:04 -05:00
Mitchell Hashimoto
b006101ddd lib-vt: boilerplate to build a shared object 2025-09-23 12:35:39 -07:00
Gautier Ben Aïm
b0e85d900e use build.zig.zon instead 2025-09-23 21:14:09 +02:00
Mitchell Hashimoto
f97518cc10 example/zig-vt: add comment explaining how to get zero-dep build 2025-09-23 11:55:44 -07:00
Gautier Ben Aïm
a96cb9ab57 chore: pin zig 0.14.1 in .zigversion 2025-09-23 20:42:57 +02:00
Mitchell Hashimoto
31af87e021 macOS: Convert Sources to folder references (#8856)
https://github.com/ghostty-org/ghostty/discussions/8855
2025-09-23 11:29:32 -07:00
Leah Amelia Chen
2a24918eec deps: removing utf8proc (#8866) 2025-09-23 20:05:03 +02:00
Paal Øye-Strømme
bd9bc5f1b9 deps: removing utf8proc
utf8proc is no longer being used

Per #808, it should be removed.

Link: https://github.com/ghostty-org/ghostty/discussions/6931
Link: https://github.com/ghostty-org/ghostty/discussions/2563
2025-09-23 17:38:03 +02:00
Lars
9072bab6b8 Update iOS membership exceptions 2025-09-23 16:50:13 +02:00
Jacob Sandlund
c7ad29ca91 move tests over to _uucode.zig files to avoid needing deps for vt tests 2025-09-23 10:49:59 -04:00
Jacob Sandlund
b5c6c044a7 Fix merge 2025-09-23 10:01:23 -04:00
Jacob Sandlund
c2a9c5ee5b fix comment 2025-09-23 09:48:09 -04:00
Mitchell Hashimoto
f8472cb32b feat: list-themes cursor and selection colors (#8848)
Closes #8446

Adds the remaining theme colors: cursor-color, cursor-text,
selection-background, and selection-foreground.

## Before
<img width="1840" height="1195" alt="image"
src="https://github.com/user-attachments/assets/f39f0cf1-f1c4-468c-a706-a39e3efe2883"
/>

## After
<img width="1840" height="1195" alt="image"
src="https://github.com/user-attachments/assets/a6995c35-070d-4971-9caf-ebae994deba5"
/>
2025-09-23 06:47:49 -07:00
Mitchell Hashimoto
0bbe39fb0a ci: fix missing var name 2025-09-23 06:45:03 -07:00
Jacob Sandlund
7386dae079 use unicode.graphemeBreak in src/font/shaper/web_canvas.zig 2025-09-23 09:43:28 -04:00
Mitchell Hashimoto
52c0afcc93 ci: Add test for building with i18n on and off (#8858)
Closes #8360
2025-09-23 06:42:12 -07:00
Mitchell Hashimoto
862e19cbab deps: Allow dynamic-linking of spirv-cross (#8859)
- Use the pkg-config name of 'spirv-cross-c-shared' exported by the
upstream SPIRV-Cross build
https://github.com/KhronosGroup/SPIRV-Cross/blob/main/pkg-config/spirv-cross-c-shared.pc.in
2025-09-23 06:38:43 -07:00
Jacob Sandlund
b01770c21c Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-23 09:36:41 -04:00
azhn
a9c5a05e5b deps: Allow dynamic-linking of spirv-cross
- Use the pkg-config name of 'spirv-cross-c-shared' exported by the upstream SPIRV-Cross build
2025-09-23 20:49:22 +10:00
azhn
aa52e11c34 ci: Add test for building with i18n on and off 2025-09-23 20:03:26 +10:00
Kat
3eb646ea6b Add zh_TW Traditional Chinese locale (#6773)
🎉
2025-09-23 08:33:46 +00:00
Lars
131f4fb8b1 Convert Sources to folder references 2025-09-23 09:30:49 +02:00
rhodes-b
a584163306 load runtime css before user options 2025-09-22 23:14:05 -05:00
Mitchell Hashimoto
e951dedc66 GTK Fix unfocused-split-fill (#8813)
Attempts a resolution for
https://github.com/ghostty-org/ghostty/discussions/8572

This matches the behavior of the old GTK apprt where
unfocused-split-fill /opacity doesn't apply when there is only one
active surface.
2025-09-22 19:58:50 -07:00
rhodes-b
36e09cdbe1 remove debug print from helping something with graphics issues 2025-09-22 21:30:03 -05:00
rhodes-b
f36ccc4866 remove is_split properity in priv since it has a getter method 2025-09-22 21:22:53 -05:00
CoderJoshDK
2aad450d2e feat: list-themes cursor and selection colors 2025-09-22 21:18:37 -04:00
Mitchell Hashimoto
8cb52323e5 ghostty-vt Zig Module (#8840)
This makes a `ghostty-vt` Zig module available from our `build.zig` that
contains a reusable Zig API version of our core terminal emulation layer
including escape sequence parsing, terminal state, and screen state.
This is the groundwork for phase one of my "libghostty" vision.

With SIMD disabled, `ghostty-vt` has no dependencies -- not even on libc
-- and can produce fully static standalone binaries. With SIMD enabled,
`ghostty-vt` only depends on libc.

The point of this PR is primarily to get the bug fixes I found in and to
get this running in CI on every commit so that we don't regress it. In
the future we'll do more (see the future section below).

> [!WARNING]
> **The API is extremely not stable and will definitely change in the
future.** The _functionality/logic_ is very stable, because it's the
same core logic used by Ghostty, but the API itself is not at all. For
this PR, we mostly just expose everything and we'll reshape the API
later.

## What is `libghostty-vt`? 

I've stated my vision for a `libghostty` for some time. You can find
background on that. Recently, I've realized that the _scope_ of
`libghostty` is way too large to ship as a single unit. To that end,
`libghostty` will be split into smaller scoped sub-libraries (that may
depend on each other for higher level functionality). The exact mapping
is being worked out.

**The first library I'm extracting is `libghostty-vt` (both Zig and C,
this PR starts with Zig).** This will be a library focused only on core
terminal emulation, terminal state, and screen state. It lacks rendering
support and input handling.

**But why?** The core terminal emulation is the primary source of both
missing functionality and bugs within terminal emulators. Look at this
[simple bug in jediterm](https://github.com/JetBrains/jediterm/pull/311)
that fails to parse a trivially common sequence resulting in horrendous
misrenders. Jediterm is used by every JetBrains IDE! Literally the core
terminal in a many-millions-of-dollars business!

`libghostty-vt` is a _zero dependency_ terminal emulation layer that
exposes a C API which will let any popular language build bindings so
that we can stop reinventing the terminal emulation layer and get best
in class (or near it) terminal emulation capabilities everywhere.

## In This PR

- `ghostty-vt` Zig module
- Example usage of it in `example/zig-vt`
- CI to run Zig module tests, test that our examples build, and test
SIMD on/off
- New feature build flag `-Dsimd` (default on) that turns SIMD on or off
- Unexposed feature flag that allows building the core terminal logic
without regex support (default on right now jus for the ghostty-vt
module as I figure out what our future regex story is in a post-oni
world).
- Fixes for non-SIMD builds

## Future

There's a lot to do in the future outside of this PR:

- Define a more stable Zig API
- Define a C API at all
- Figure out our regex engine story
- Documentation improvements
2025-09-22 10:06:36 -07:00
Mitchell Hashimoto
c177716ac6 build: some docs 2025-09-22 09:53:22 -07:00
Mitchell Hashimoto
8477b6a21a simd: scalar base64 ignores invalid padding 2025-09-22 09:44:58 -07:00
Mitchell Hashimoto
530633b9e9 simd: fix scalar utf8 decoding 2025-09-22 09:29:08 -07:00
Mitchell Hashimoto
5a29dd3ef5 build: make build_options generally available 2025-09-22 08:35:44 -07:00
Mitchell Hashimoto
6893024c51 simd: add scalar fallbacks to all for build_options.simd false 2025-09-22 08:26:53 -07:00
Mitchell Hashimoto
8aa4373aaf ci: add simd on/off test 2025-09-22 06:48:07 -07:00
Lars
8beeebc21d Force Ghostty to be active if not 2025-09-22 15:27:27 +02:00
Lars
8600954526 Workaround for #8669 2025-09-22 14:52:10 +02:00
rhodes-b
fd9014952f use getter to notify is-split property 2025-09-21 22:59:42 -05:00
Mitchell Hashimoto
9c92c3bb81 fastmem non-libc needs to use copyBackwards if dest > src
This fixes test failures when Ghostty's core is run without libc. 
Ghostty in the real world (all built executables) require libc so this
bug has never been hit before, but I'm working on a libc-less core and
this caused real test failures (so its already tested, as well).
2025-09-21 20:48:18 -07:00
Mitchell Hashimoto
dfda3ac280 ci: fix example build 2025-09-21 20:39:43 -07:00
Mitchell Hashimoto
3e1ba35843 terminal: fix mistaken gtk logic 2025-09-21 20:29:18 -07:00
Mitchell Hashimoto
14eb8aa4e4 Add simd flag for disabling SIMD functionality 2025-09-21 20:27:34 -07:00
Mitchell Hashimoto
f42656b0ac lib-vt: require libc for now 2025-09-21 19:59:23 -07:00
Mitchell Hashimoto
645520b502 ci: build examples in CI 2025-09-21 19:54:11 -07:00
Mitchell Hashimoto
3e34009492 lib-vt: expose all of terminal for now 2025-09-21 19:50:42 -07:00
Mitchell Hashimoto
64f26c14d3 example/zig-vt 2025-09-21 19:41:58 -07:00
Mitchell Hashimoto
1758f962f6 remove stale example wasm app 2025-09-21 19:40:00 -07:00
Mitchell Hashimoto
4f974f4278 terminal: don't build StringMap.searchIterator without regex support 2025-09-21 19:40:00 -07:00
Mitchell Hashimoto
811f9f05d0 terminal: support disabling kitty graphics protocol 2025-09-21 19:40:00 -07:00
Mitchell Hashimoto
1b46884e72 terminal: add build option for oniguruma, which controls tmux cc mode 2025-09-21 19:39:59 -07:00
Mitchell Hashimoto
a42193b997 start extracting core terminal zig module 2025-09-21 19:39:58 -07:00
Mitchell Hashimoto
485b6b73bf build(deps): bump vmactions/freebsd-vm from 1.2.3 to 1.2.4 (#8827)
Bumps [vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm)
from 1.2.3 to 1.2.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vmactions/freebsd-vm/releases">vmactions/freebsd-vm's
releases</a>.</em></p>
<blockquote>
<p>add 15.0</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="487ce35b96"><code>487ce35</code></a>
Update from base vm</li>
<li><a
href="81b0e85cca"><code>81b0e85</code></a>
Generated from base-vm</li>
<li><a
href="4f22df8b8d"><code>4f22df8</code></a>
add 15</li>
<li><a
href="11ecb20fda"><code>11ecb20</code></a>
Update from base vm</li>
<li><a
href="ec67fecd18"><code>ec67fec</code></a>
Generated from base-vm</li>
<li><a
href="709b36f060"><code>709b36f</code></a>
Update version to</li>
<li>See full diff in <a
href="05856381fa...487ce35b96">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=vmactions/freebsd-vm&package-manager=github_actions&previous-version=1.2.3&new-version=1.2.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 merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-21 19:38:54 -07:00
Mitchell Hashimoto
6c160844b9 build(deps): bump cachix/install-nix-action from 31.6.1 to 31.6.2 (#8828)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.6.1 to 31.6.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/cachix/install-nix-action/releases">cachix/install-nix-action's
releases</a>.</em></p>
<blockquote>
<h2>v31.6.2</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.31.1 -&gt; 2.31.2 by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/cachix/install-nix-action/pull/256">cachix/install-nix-action#256</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31...v31.6.2">https://github.com/cachix/install-nix-action/compare/v31...v31.6.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a809471b5c"><code>a809471</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/256">#256</a>
from cachix/create-pull-request/patch</li>
<li><a
href="d5f1c043d0"><code>d5f1c04</code></a>
nix: 2.31.1 -&gt; 2.31.2</li>
<li>See full diff in <a
href="7be5dee142...a809471b5c">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.6.1&new-version=31.6.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@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>
2025-09-21 19:38:25 -07:00
Mitchell Hashimoto
1de584f32c xdg: treat empty env vars as not existing (#8830)
Replaces #8786 

The author of the original PR used AI agents to create that PR. To the
extent that this PR borrows code from that PR (mostly in the tests) AI
was used in the creation of this PR.
2025-09-21 19:38:14 -07:00
Daniel Wennberg
f2fcbd6e5e Add missing codepoints to isPowerline predicate
e0d6 and e0d7 were left out.

Also collapsed everything to a single range; unlikely that the unused
gaps (e0c9, e0cb, e0d3, e0d5) would be used for something else in any
font that ships Powerline glyphs.
2025-09-21 19:00:35 -07:00
Jeffrey C. Ollie
e9c18ff6db xdg: treat empty env vars as not existing 2025-09-21 20:57:00 -05:00
rhodes-b
4e7f847d03 remove setIsSplit in surface class 2025-09-21 20:37:47 -05:00
rhodes-b
fdcaeebb99 bind is-split property between split_tree class and surface class 2025-09-21 20:35:20 -05:00
dependabot[bot]
a63864d8df build(deps): bump cachix/install-nix-action from 31.6.1 to 31.6.2
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.6.1 to 31.6.2.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](7be5dee142...a809471b5c)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-22 00:07:00 +00:00
dependabot[bot]
3a4f7b3d0f build(deps): bump vmactions/freebsd-vm from 1.2.3 to 1.2.4
Bumps [vmactions/freebsd-vm](https://github.com/vmactions/freebsd-vm) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/vmactions/freebsd-vm/releases)
- [Commits](05856381fa...487ce35b96)

---
updated-dependencies:
- dependency-name: vmactions/freebsd-vm
  dependency-version: 1.2.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-22 00:06:51 +00:00
Daniel Wennberg
d1db596039 Add box drawing characters to the min contrast exclusion 2025-09-21 17:01:58 -07:00
Daniel Wennberg
2f19d6bb73 Treat Powerline glyphs like normal characters
...not whitespace. Powerline glyphs can be considered an extension of
the Block Elements unicode block, which is neither whitespace nor
symbols (icons).

This ensures that characters immediately followed by a powerline glyph
are constrained to a single cell (unlike the current behavior where a PL
glyph is considered whitespace), while symbols (icons) immediately
preceded by a powerline glyph are not (unlike if a PL glyph were
considered a symbol). This resolves
https://discord.com/channels/1005603569187160125/1417236683266592798
2025-09-21 17:01:58 -07:00
Daniel Wennberg
13d44129bf Add constraint width tests 2025-09-21 16:39:17 -07:00
Mitchell Hashimoto
bc95317ba4 build: many more lazy dependencies, defer deps add unless needed (#8826)
This makes more dependencies lazy. This has a practical effect of
reducing the number of dependencies that need to be downloaded when
running certain zig build steps.

This is all limited because we're blocked on an upstream Zig issue:
https://github.com/ziglang/zig/issues/21525 This prevents us from fully
avoiding downloading many dependencies, but at least they're relatively
small.

One major improvement here is the usage of `lazyImport` for
`zig-wayland` that prevents downloading `zig_wayland` unconditionally on
all platforms. On macOS, we don't download this at all anymore.

Another, weirder change is that all our transitive dependencies are now
marked lazy (e.g. glslang's upstream source) even if the glslang build
always requires it. This was necessary because without this, even if we
simply referenced glslang in the root build.zig, it would force the
source package to download unconditionally. This no longer happens.

cc @pluiedev Minor improvements here, doesn't change the long term plan,
but improves things in the interim.
2025-09-21 13:43:31 -07:00
Mitchell Hashimoto
17498ce122 build: many more lazy dependencies, defer deps add unless needed
This makes more dependencies lazy. This has a practical effect of
reducing the number of dependencies that need to be downloaded when
running certain zig build steps.

This is all limited because we're blocked on an upstream Zig issue:
https://github.com/ziglang/zig/issues/21525 This prevents us from
fully avoiding downloading many dependencies, but at least they're
relatively small.

One major improvement here is the usage of `lazyImport` for
`zig-wayland` that prevents downloading `zig_wayland` unconditionally on
all platforms. On macOS, we don't download this at all anymore.

Another, weirder change is that all our transitive dependencies are now
marked lazy (e.g. glslang's upstream source) even if the glslang build
always requires it. This was necessary because without this, even if we
simply referenced glslang in the root build.zig, it would force the
source package to download unconditionally. This no longer happens.
2025-09-21 13:26:09 -07:00
Mitchell Hashimoto
09b37e3b24 flatpak: update GNOME runtime to 49 (#8825)
Notable dependencies changes:

- blueprint-compiler is dropped as it has been bundled in the SDK
- GTK 4.18.6 -> 4.20.1
- libadwaita 1.7.7 -> 1.8.0
2025-09-21 13:07:36 -07:00
Leorize
4ff74fdfae flatpak: update GNOME runtime to 49
Notable dependencies changes:

- blueprint-compiler is dropped as it has been bundled in the SDK
- GTK 4.18.6 -> 4.20.1
- libadwaita 1.7.7 -> 1.8.0
2025-09-21 14:17:48 -05:00
Daniel Wennberg
52ef17d4e0 Hoist GlyphSize out of nested scopes 2025-09-21 11:32:41 -07:00
Peter Dave Hello
1a189787ae Add zh_TW Traditional Chinese locale 2025-09-22 00:13:15 +08:00
Mitchell Hashimoto
25aaca5a6f Update iTerm2 colorschemes (#8812)
Upstream release:
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/tag/release-20250916-134637-76894f0
2025-09-21 07:25:05 -07:00
Mitchell Hashimoto
1a6af17041 gtk: restore flatpak-aware resource directory support (#8816)
This was not ported to gtk-ng before old runtime was removed, breaking
shell integration on Flatpak.

This implementation is copied verbatim from old runtime.
2025-09-21 07:02:47 -07:00
Kat
b52553de24 Update README_TRANSLATORS to reflect the new i18n locales struct path (#8819)
It was moved in 9feaec9c9c (#8798), but
the documentation seems to have been forgotten.
2025-09-21 11:57:56 +00:00
Kat
f6c1653dee Update README_TRANSLATORS to reflect the new i18n locales struct path.
It was moved in 9feaec9c9c, but the documentation
seems to have been forgotten.
2025-09-21 11:42:32 +00:00
Leah Amelia Chen
055a007926 Default config template be explicit that you do not copy the default values (#8701) 2025-09-21 10:59:45 +02:00
Leorize
cf0557a093 gtk: restore flatpak-aware resource directory support
This was not ported to gtk-ng before old runtime was removed, breaking
shell integration on Flatpak.
2025-09-21 02:11:41 -05:00
Mitchell Hashimoto
fcd0f88024 unicode: delete props.zig and clean up symbols deps too (#8814)
Follow up to #8810

Same reasoning.
2025-09-20 21:07:23 -07:00
rhodes-b
3254bb41d5 fix typo 2025-09-20 22:49:35 -05:00
rhodes-b
1c59ed5d60 comment for the n_siblings surface member 2025-09-20 22:47:50 -05:00
rhodes-b
3d3551d1ed add n_siblings member, and when splits are created / removed update the number of siblings for the remaining nodes 2025-09-20 22:45:17 -05:00
Mitchell Hashimoto
10dc9353b7 unicode: delete props.zig and clean up symbols deps too
Follow up to #8810

Same reasoning.
2025-09-20 20:28:25 -07:00
rhodes-b
42fc42de2d fix surface blueprint formatting 2025-09-20 21:45:01 -05:00
rhodes-b
180cc31d87 fix comments to specific the config option 2025-09-20 21:41:15 -05:00
rhodes-b
fa5a44e591 apply unfocused-split with surface blueprint 2025-09-20 21:37:59 -05:00
rhodes-b
cfcd11863e rename setUnfocused to setUnfocusedFill 2025-09-20 20:24:51 -05:00
rhodes-b
52c2f02fa4 use focus signal in split_tree to determine if we apply unfocused-split-fill 2025-09-20 20:18:28 -05:00
mitchellh
6e1eb67d94 deps: Update iTerm2 color schemes 2025-09-21 00:15:05 +00:00
Mitchell Hashimoto
511314e1a1 unicode: isolate properties, tables, and ziglyph into separate files (#8810)
This makes it cleaner visually where the separation of concerns is.
There is now the generic `Properties.zig`, and then the
implementation-specific `props_<impl>.zig` files. Despite Zig's lazy
analysis, I find this is much easier to understand as a human.

Doing this resulted in finding one part in `src/terminal` where we were
still inadvertently using ziglyph directly instead of our LUTs! I
switched this out.

After this PR, `src/terminal` as a standalone module no longer depends
on `ziglyph` at all.[^1]

cc @jacobsandlund this is going to cause conflicts in your PR. I'm sorry
about that. But it should make it cleaner to bring in the uucode work by
adding a dedicated `props_uucode.zig` file!

[^1]: Why would I be talking about `src/terminal` as a standalone
module? That's interesting.
2025-09-20 15:15:15 -07:00
Mitchell Hashimoto
a96b2abf7c update to the latest zon2nix (#8808) 2025-09-20 15:11:34 -07:00
Jeffrey C. Ollie
d4bc73a9d6 update to the latest zon2nix 2025-09-20 17:02:24 -05:00
Mitchell Hashimoto
bf1278deff unicode: isolate properties, tables, and ziglyph into separate files
This makes it cleaner to add new sources of table generation and also
avoids inadvertently depending on different modules (despite Zig's lazy
analysis). 

This also fixes up terminal to only use our look up tables which avoids
bringing ziglyph in for the terminal module.
2025-09-20 15:00:55 -07:00
Mitchell Hashimoto
c277ef8d82 gtk: use zig-gobject generated from ghostty-org/zig-gobject (#8802) 2025-09-20 12:38:54 -07:00
rhodes-b
6ee9a3767b worse way but its at least split aware, doesn't seem like the path forward 2025-09-20 04:32:09 -05:00
rhodes-b
b34e22053d unfocused-split-fill working again though it can't detect when its actually a split yet 2025-09-20 03:55:05 -05:00
rhodes-b
f0e407de85 nicer comment on why you shouldn't copy the defaults into your config specifically that some options will conflict with each other 2025-09-20 02:28:07 -05:00
Jeffrey C. Ollie
fbaacc235b gtk: use zig-gobject generated from ghostty-org/zig-gobject 2025-09-20 01:39:59 -05:00
Mitchell Hashimoto
f6e4a2888a Snap: Do not leak snap variables or snap paths into children (#8771)
Avoid leaking snap environment values and in particular the `$SNAP*`
values to the children that we run from the terminal.

Do this programmatically instead of the launcher, since ghostty needs
know the environment it runs in, while it must not leak the info to the
children.

We've also another leak on snap, that creates a more visible problem
(wrong matching of children applications) that is the apparmor security
profile.

I've handled it at
cc3b46f600
but that requires some love in order to fully decouple the snap option
to the build, to avoid including it in non-snap builds, so an help would
be appreciated there.

> This PR was contains code (in `filterSnapPaths`) that was improved by
DeepSeek.
2025-09-19 16:12:30 -07:00
Mitchell Hashimoto
270891eee1 ci: add -Dsnap test 2025-09-19 16:07:55 -07:00
Mitchell Hashimoto
7b8be344fc stylistic changes 2025-09-19 16:03:49 -07:00
Marco Trevisan (Treviño)
bf3a607db6 build: Add a new snap option and use it to build the snap
So we can limit the snap operations even at build time
2025-09-19 15:55:14 -07:00
Marco Trevisan (Treviño)
d55f3e5c41 gtk/surface: Filter out the SNAP variables by their contents
When running in a snap context we need to filtering out all the SNAP_*
variables out there, but this is not enough, because it's also needed
to sanitize them by ensuring that no variable containing a path pointing
to a $SNAP folder is leaked there.

Otherwise we might have (for example) XDG_RUNTIME_DIRS containing a
"private" snap path, and that will be exposed to all the applications
that will be started from ghostty
2025-09-19 15:54:52 -07:00
Marco Trevisan (Treviño)
2de105e035 snap: Do not leak the launcher into the ghostty $PATH
Otherwise when launching the snap we'll get a "launcher" binary that is
provided by the own snap
2025-09-19 15:54:52 -07:00
Mitchell Hashimoto
944f206b76 build: lower build.zig dependencies to improve caching (#8798)
This is stomping towards minimizing our build.zig dependencies so that
it can be cached more often. Right now, touching almost any file in the
project forces the build.zig to rebuild which is destroying my
productivity.

The first set of work is to move all our completion and syntax file
generation into a data generator exe, e.g. vim, zsh, fish, etc. This
might seem like just shuffling bits but it results in a real tangible
improvement: when you run `zig build test`, we no longer have to rebuild
our `build.zig` when you for example... modify a CLI action.

This is just a small improvement. Our build.zig depends on way too much
stuff, so this PR will be draft while I continue to use commits to
separate out scopes of change.
2025-09-19 15:46:02 -07:00
Mitchell Hashimoto
da2a3e2510 very slightly improve helpgen dependencies 2025-09-19 15:41:14 -07:00
Mitchell Hashimoto
9feaec9c9c build: move locales out into dedicated file 2025-09-19 15:28:25 -07:00
Mitchell Hashimoto
d65466362d build: Command.expandPath can go in its own dedicated os/path.zig file 2025-09-19 15:22:10 -07:00
Mitchell Hashimoto
800fa99ff2 build: move apprt, font, renderer enums to dedicated files
This reduces the surface area of files we depend on for builds.
2025-09-19 15:17:41 -07:00
Mitchell Hashimoto
bf047032b5 build: generate various resources at build run, not build graph
This is stomping towards minimizing our build.zig dependencies so that
it can be cached more often. Right now, touching almost any file in the
project forces the build.zig to rebuild which is destroying my
productivity.
2025-09-19 14:50:33 -07:00
Mitchell Hashimoto
999b605145 macos: quick terminal stores the last closed size by screen (#8796)
Fixes #8713

This stores the last closed state of the quick terminal by screen
pointer. We use a weak mapping so if a screen is unplugged we'll clear
the memory. We will not remember the size if you unplug and replug in a
monitor.
2025-09-19 13:14:14 -07:00
Mitchell Hashimoto
4d761c96e5 macos: quick terminal stores the last closed size by screen
Fixes #8713

This stores the last closed state of the quick terminal by screen
pointer. We use a weak mapping so if a screen is unplugged we'll clear
the memory. We will not remember the size if you unplug and replug in a
monitor.
2025-09-19 13:01:29 -07:00
Mitchell Hashimoto
3ce1239460 ci: put a 10 minute timeout on the Debian build (#8795)
This usually takes around 2 minutes. I just saw a runaway one spending
30+ minutes.
2025-09-19 12:32:49 -07:00
Mitchell Hashimoto
36ef1169f6 ci: put a 10 minute timeout on the Debian build
This usually takes around 2 minutes. I just saw a runaway one spending
30+ minutes.
2025-09-19 12:29:20 -07:00
Mitchell Hashimoto
66a2da13d4 macos: set the app icon in syncAppearance to delay the icon update (#8792)
Fixes #8734

This forces the app icon to be set on another event loop tick from the
main startup.

In the future, we should load and set the icon completely in another
thread. It appears that all the logic we have is totally thread-safe.
2025-09-19 12:16:59 -07:00
Mitchell Hashimoto
f60bdb0faa macos: set the app icon in syncAppearance to delay the icon update
Fixes #8734

This forces the app icon to be set on another event loop tick from
the main startup. 

In the future, we should load and set the icon completely in another
thread. It appears that all the logic we have is totally thread-safe.
2025-09-19 12:07:28 -07:00
Mitchell Hashimoto
55153937c6 macos: correct SurfaceView supported send/receive types for services (#8790)
Fixes #8785

This is the callback AppKit sends when it wants to know if our
application can handle sending and receiving certain types of data.

The prior implementaiton was incorrect and would erroneously claim
support over combinations that we couldn't handle (at least, at the
SurfaceView layer).

This corrects the implementation. The services we expect still show up
and the error in 8785 goes away.
2025-09-19 12:01:31 -07:00
Mitchell Hashimoto
d27bc69f2e macos: correct SurfaceView supported send/receive types for services
Fixes #8785

This is the callback AppKit sends when it wants to know if our
application can handle sending and receiving certain types of data.

The prior implementaiton was incorrect and would erroneously claim
support over combinations that we couldn't handle (at least, at the
SurfaceView layer). 

This corrects the implementation. The services we expect still show up
and the error in 8785 goes away.
2025-09-19 11:44:46 -07:00
Mitchell Hashimoto
1b6cda2b10 macos: "new tab" service should set preferred parent to ensure tab (#8784)
Fixes #8783

Our new tab flow will never have a previously focused window because its
triggered by a service so we need to use the "preferred parent" logic we
have to open this in the last focused window.
2025-09-19 10:15:04 -07:00
Mitchell Hashimoto
950d3755ff renderer/opengl: minimum contrast for black sets proper color (#8782)
Fixes #8745

When rendering black for minimum contrast we were setting opacity to 0
making it invisible.
2025-09-19 09:58:50 -07:00
Mitchell Hashimoto
6143aa8ce0 macos: "new tab" service should set preferred parent to ensure tab
Fixes #8783

Our new tab flow will never have a previously focused window because its
triggered by a service so we need to use the "preferred parent" logic we
have to open this in the last focused window.
2025-09-19 09:58:27 -07:00
Mitchell Hashimoto
d30f1537ec gtk: add glib log writer function (#8779)
This will funnel GLib/GObject/GTK logging messages through Zig's logging
system rather than just dumping them directly to stderr.
2025-09-19 09:47:06 -07:00
Mitchell Hashimoto
c42ed70758 renderer/opengl: minimum contrast for black sets proper color
Fixes #8745

When rendering black for minimum contrast we were setting opacity to 0
making it invisible.
2025-09-19 09:45:08 -07:00
Jeffrey C. Ollie
f375ec7c65 gtk: add glib log writer function
This will funnel GLib/GObject/GTK logging messages through Zig's logging
system rather than just dumping them directly to stderr.
2025-09-19 09:35:35 -05:00
Mitchell Hashimoto
122731c6e8 Optimize PNG images losslessly: 73 → 51 KiB (−30%) (#8776) 2025-09-19 07:07:57 -07:00
maximal
38c0de3aa4 Revert src/font/sprite/testdata 2025-09-19 15:00:04 +03:00
maximal
6d40da1e1c Optimize PNG images losslessly: 73 → 51 KiB (−30%) 2025-09-19 12:55:19 +03:00
Jacob Sandlund
7b0722bf16 Remove comment above test. it's not too slow 2025-09-19 01:26:17 -04:00
Jacob Sandlund
cf3b514efc pr feedback: get, remove todos for case_folding_simple 2025-09-19 01:24:13 -04:00
Mitchell Hashimoto
b9a5cad562 build: explicitly suffix Zig files 2: Electric Boogaloo (#8769)
Of *course* I missed one
2025-09-18 16:58:50 -07:00
Leah Amelia Chen
6d2576abee build: explicitly suffix Zig files 2: Electric Boogaloo
Of *course* I missed one
2025-09-19 01:23:06 +02:00
Mitchell Hashimoto
77b39c45a6 slightly improve logs (#8767)
Hello

This is a small thing I noticed when building Ghostty. The logs for
SetTitle and Pwd are unreadable due to them being shown as an array of
integers, so I added a custom formatter for them to be shows as text.
2025-09-18 15:28:24 -07:00
عبد الرحمن صباهي
d6e58ef1fc slightly improve logs 2025-09-19 01:00:17 +03:00
Mitchell Hashimoto
7875efbcb8 macos: implement bell-features=border on macOS (#8768)
https://github.com/user-attachments/assets/ac58ff8e-9ef6-4cb2-8e40-9f588aaaca4e
2025-09-18 14:51:26 -07:00
Mitchell Hashimoto
fe55d90ec5 macos: implement bell-features=border on macOS 2025-09-18 14:43:09 -07:00
Mitchell Hashimoto
2ebef2650c build: explicitly suffix generated Zig source files (#8765)
Previously we're just feeding the compiler source files generated via
capturing stdout, which all by default have the filename `stdout`. Under
some particular yet uncertain circumstances in Zig 0.14 (only factor
we've found so far is a large amount of cores/compilation shards) the
compiler will actually crash on an unreachable code path that assumes
all source files either end in .zig or .zon, causing crashes for
packagers for distros like Nixpkgs and Gentoo.

Given this has been explicitly made illegal in Zig 0.15 (see
ziglang/zig#24957) I don't really see why we shouldn't fix this for 1.2
too. We have to do this at some point no matter what anyways.
2025-09-18 14:11:32 -07:00
Mitchell Hashimoto
050188fc12 macos: bell-features=title works again (#8766)
This was a regression we didn't fix before 1.2.
2025-09-18 14:11:22 -07:00
Daniel Wennberg
333a32208e Factor out glyph rect function 2025-09-18 14:05:12 -07:00
Mitchell Hashimoto
ad92bf7ab5 macos: bell-features=title works again
This was a regression we didn't fix before 1.2.
2025-09-18 14:02:32 -07:00
Leah Amelia Chen
9b40e03c40 build: explicitly suffix generated Zig source files
Previously we're just feeding the compiler source files generated via
capturing stdout, which all by default have the filename `stdout`.
Under some particular yet uncertain circumstances in Zig 0.14 (only
factor we've found so far is a large amount of cores/compilation shards)
the compiler will actually crash on an unreachable code path that assumes
all source files either end in .zig or .zon, causing crashes for packagers
for distros like Nixpkgs and Gentoo.

Given this has been explicitly made illegal in Zig 0.15
(see ziglang/zig#24957) I don't really see why we shouldn't fix this for
1.2 too. We have to do this at some point no matter what anyways.
2025-09-18 23:02:03 +02:00
Mitchell Hashimoto
da9334dce5 macos: opening filepaths should make proper file URLs (#8764)
Fixes #8763
2025-09-18 13:37:02 -07:00
Mitchell Hashimoto
4fa8b8f285 macos: opening filepaths should make proper file URLs
Fixes #8763
2025-09-18 13:28:27 -07:00
Mitchell Hashimoto
834fe17abb macos: set initial window in TerminalWindow awakeFromNib (#8762)
Maybe fixes #8736

I thought `windowDidLoad` was early on because its before the window is
shown but apparently not. Let's try `awakeFromNib` which is called just
after the window is loaded from the nib. It is hard to get any earlier
than that.
2025-09-18 13:10:28 -07:00
Mitchell Hashimoto
734d1a13b3 macos: set initial window in TerminalWindow awakeFromNib
Maybe fixes #8736

I thought `windowDidLoad` was early on because its before the window is
shown but apparently not. Let's try `awakeFromNib` which is called
just after the window is loaded from the nib. It is hard to get any
earlier than that.
2025-09-18 13:05:57 -07:00
Mitchell Hashimoto
92effb37db documentation: fix MacOSDockDropBehavior valid values (#8752)
The documentation shows that the enum values should be "new-window" and
"new-tab",
However, "new-window" currently fails, but "window" is still accepted.
2025-09-18 12:46:54 -07:00
Daniel Wennberg
8fe9c579ef Drop the nan sentinel; just fall through instead 2025-09-18 12:39:19 -07:00
Daniel Wennberg
4af4e18725 Use approximate equality for float comparisons 2025-09-18 12:34:32 -07:00
Mitchell Hashimoto
38dcf0ab59 macos: window-position-x/y are from top-left corner (#8760)
Fixes #8672

Almost fully written by AI:
https://ampcode.com/threads/T-86df68a3-578c-4a1c-91f3-788f8b8f0aae

I reviewed all the code.
2025-09-18 12:27:35 -07:00
Mitchell Hashimoto
773990ada3 macos: window-position-x/y are from top-left corner
Fixes #8672

Almost fully written by AI: https://ampcode.com/threads/T-86df68a3-578c-4a1c-91f3-788f8b8f0aae

I reviewed all the code.
2025-09-18 12:18:13 -07:00
Jacob Sandlund
4fc8faa01e Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-18 14:27:33 -04:00
Jacob Sandlund
b83315cb81 set max for unicode grapheme executable 2025-09-18 14:26:04 -04:00
Jacob Sandlund
6bd5da7354 update commented out test 2025-09-18 14:24:24 -04:00
Jacob Sandlund
83f387d735 default log level 2025-09-18 14:21:39 -04:00
Jacob Sandlund
18e9989f63 forgot to align buf 2025-09-18 14:20:41 -04:00
Mitchell Hashimoto
354b62d5ce macos: add progress bar to iOS target 2025-09-18 10:48:29 -07:00
Mitchell Hashimoto
9f6991f9db macos: custom progress bar to workaround macOS 26 ProgressView bugs (#8753)
Fixes #8731

The progress view in macOS 26 is broken in ways we can't work around
directly. Instead, we must create our own custom progress bar. Luckily,
our usage of the progress view is very simple.



https://github.com/user-attachments/assets/fb3dd271-0830-49fa-97ce-48eb5514e781

This was written mostly by Amp. I made my own modifications and fully
understand the code. Threads below.

Amp threads:
https://ampcode.com/threads/T-88b550b7-5e0d-4ab9-97d9-36fb63d18f21
https://ampcode.com/threads/T-721d6085-21d5-497d-b6ac-9f203aae0b94
2025-09-18 10:31:48 -07:00
Mitchell Hashimoto
058d6808c1 macos: custom progress bar to workaround macOS 26 ProgressView bugs
Fixes #8731

The progress view in macOS 26 is broken in ways we can't work around
directly. Instead, we must create our own custom progress bar. Luckily,
our usage of the progress view is very simple.

Amp threads:
https://ampcode.com/threads/T-88b550b7-5e0d-4ab9-97d9-36fb63d18f21
https://ampcode.com/threads/T-721d6085-21d5-497d-b6ac-9f203aae0b94
2025-09-18 10:22:54 -07:00
Mitchell Hashimoto
6ed00b1217 renderer: create explicit sampler state for custom shaders (#8751)
The GLSL to MSL conversion process uses a passed-in sampler state for
the `iChannel0` parameter and we weren't providing it. This magically
worked on Apple Silicon for unknown reasons but failed on Intel GPUs.

In normal, hand-written MSL, we'd explicitly create the sampler state as
a normal variable (we do this in `shaders.metal` already!), but the
Shadertoy conversion stuff doesn't do this, probably because the exact
sampler parameters can't be safely known.

This fixes a Metal validation error when using custom shaders:

```
-[MTLDebugRenderCommandEncoder validateCommonDrawErrors:]:5970: failed 
assertion `Draw Errors Validation Fragment Function(main0): missing Sampler 
binding at index 0 for iChannel0Smplr[0].
```

This wasn't a simple error message, the assertion would cause Xcode 26
to halt the program at that point.
2025-09-18 09:31:17 -07:00
Mitchell Hashimoto
a453681615 renderer: create explicit sampler state for custom shaders
The GLSL to MSL conversion process uses a passed-in sampler state for
the `iChannel0` parameter and we weren't providing it. This magically
worked on Apple Silicon for unknown reasons but failed on Intel GPUs.

In normal, hand-written MSL, we'd explicitly create the sampler state as
a normal variable (we do this in `shaders.metal` already!), but the
Shadertoy conversion stuff doesn't do this, probably because the exact
sampler parameters can't be safely known.

This fixes a Metal validation error when using custom shaders:

```
-[MTLDebugRenderCommandEncoder validateCommonDrawErrors:]:5970: failed 
assertion `Draw Errors Validation Fragment Function(main0): missing Sampler 
binding at index 0 for iChannel0Smplr[0].
```
2025-09-18 09:25:37 -07:00
Daniel Wennberg
bb607e0999 Refactor load flags into a function 2025-09-18 09:16:32 -07:00
Matthias von Arx
a22a1771b5 documentation: fix MacOSDockDropBehavior valid values 2025-09-18 18:09:10 +02:00
Jacob Sandlund
69594119c3 fix up diff from benchmarks, and add tests against ziglyph 2025-09-18 11:46:05 -04:00
Mitchell Hashimoto
a3643f8f52 renderer/metal: provide MTLTextureUsage render target for custom shaders (#8749)
This fixes a Metal validation error in Xcode when using custom shaders.
I suspect this is one part of custom shaders not working properly on
Intel macs (probably anything with a discrete GPU).

This happens to work on Apple Silicon but this is undefined behavior and
we're just getting lucky.

There is one more issue I'm chasing down that I think is also still
blocking custom shaders working on Intel macs.
2025-09-18 07:51:12 -07:00
Mitchell Hashimoto
cb0e60c3e5 renderer/metal: provide MTLTextureUsage render target for custom shaders
This fixes a Metal validation error in Xcode when using custom shaders. 
I suspect this is one part of custom shaders not working properly on
Intel macs (probably anything with a discrete GPU).

This happens to work on Apple Silicon but this is undefined behavior and
we're just getting lucky.

There is one more issue I'm chasing down that I think is also still
blocking custom shaders working on Intel macs.
2025-09-18 07:29:26 -07:00
Jacob Sandlund
285a33fbc0 nix update and remove extra benchmark files 2025-09-18 09:29:22 -04:00
Jacob Sandlund
3275903611 update uucode and cleanups 2025-09-18 09:26:09 -04:00
Jacob Sandlund
ec5e1e504d Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-18 08:46:08 -04:00
Daniel Wennberg
03a707b2c0 Add tests for font metrics and their estimators 2025-09-17 23:04:59 -07:00
Daniel Wennberg
e1b2f6f021 Use same hinting flags for measurement and rendering 2025-09-17 23:04:59 -07:00
Daniel Wennberg
cc165990ec Use outline bbox for ascii_height measurement 2025-09-17 22:51:12 -07:00
Daniel Wennberg
3a7e7f905b Give the autoformatter what it wants 2025-09-17 22:03:00 -07:00
Mitchell Hashimoto
1efde5caba font: Measure ascii height and use to upper bound ic_width (#8720)
Measure the ~actual height between the ascender and descender lines as
the height of the~ overall bounding box of the font's ASCII
characters[^1], and use this to upper bound the IC width estimate. This
ensures that the scaling of fallback CJK fonts to a wide-aspect primary
font doesn't result in oversized CJK glyphs.

Fixes #8709.

I'd appreciate feedback from Chinese speakers on the suitability of this
metric across a variety of primary fonts.

Screenshots using an empty Ghostty config on macOS and the test file
from #8651. The font loaded as fallback for CJK is PingFang SC.

**1.2.0**
<img width="592" height="301" alt="Screenshot 2025-09-17 at 09 51 43"
src="https://github.com/user-attachments/assets/e553885d-009a-4205-88c9-24747b195211"
/>

**This PR**
<img width="592" height="301" alt="Screenshot 2025-09-17 at 09 51 25"
src="https://github.com/user-attachments/assets/3a8e8d95-ec0a-4d23-a5f0-85b2f47253e3"
/>

[^1]: Note that this may be different from the difference between the
nominal ascent - descent, as non-letter ASCII characters often exceed
the ascender and descnder lines, and fonts often bake the line gap into
the ascent/descent and set `line_gap` to zero, as per official
recommendations like those from Google Fonts:
https://simoncozens.github.io/gf-docs/metrics.html
2025-09-17 14:19:04 -07:00
Daniel Wennberg
6781fbda93 Measure ascii height and use to upper bound ic_width 2025-09-17 12:44:42 -07:00
rhodes-b
55ac946fff more info on do NOT copy default config 2025-09-17 02:41:20 -05:00
Jacob Sandlund
ae21e2c8cf Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-17 02:34:06 -04:00
Mitchell Hashimoto
0f0a61c38d selection scrolling should only depend on y value (#8686)
Fixes #8683

The selection scrolling logic should only depend on the y value of the
cursor position, not the x value. This presents unwanted scroll
behaviors, such as reversing the scroll direction which was just a side
effect of attempting to scroll tick to begin with.
2025-09-16 16:37:31 -07:00
Mitchell Hashimoto
4f47138ea3 selection scrolling should only depend on y value
Fixes #8683

The selection scrolling logic should only depend on the y value of the
cursor position, not the x value. This presents unwanted scroll
behaviors, such as reversing the scroll direction which was just a side
effect of attempting to scroll tick to begin with.
2025-09-16 16:33:49 -07:00
Mitchell Hashimoto
a098816709 font-size reloads at runtime if the font wasn't manually set (#8680)
This was a very common pitfall for users. The new logic will reload the
font-size at runtime, but only if the font wasn't manually set by the
user using actions such as `increase_font_size`, `decrease_font_size`,
or `set_font_size`. The `reset_font_size` action will reset our state to
assume the font-size wasn't manually set.

This was requested by the Omarchy project since their themes also can
adjust font size. It makes sense to me.

I also updated a comment about `font-family` not reloading at runtime;
this wasn't true even prior to this commit.
2025-09-16 15:45:23 -07:00
Mitchell Hashimoto
67992fde91 font-size reloads at runtime if the font wasn't manually set
This was a very common pitfall for users. The new logic will reload the
font-size at runtime, but only if the font wasn't manually set by the
user using actions such as `increase_font_size`, `decrease_font_size`,
or `set_font_size`. The `reset_font_size` action will reset our state
to assume the font-size wasn't manually set.

I also updated a comment about `font-family` not reloading at runtime;
this wasn't true even prior to this commit.
2025-09-16 15:39:34 -07:00
Mitchell Hashimoto
abec922d91 config: fix binding parsing to allow values containing = (#8675)
Fixes #8667

The binding `a=text:=` didn't parse properly.

This is a band-aid solution. It works and we have test coverage for it
thankfully. Longer term we should move the parser to a fully
state-machine based parser that parses the trigger first then the
action, to avoid these kind of things.
2025-09-16 13:57:22 -07:00
Mitchell Hashimoto
f7e622e8af config: fix binding parsing to allow values containing =
Fixes #8667

The binding `a=text:=` didn't parse properly.

This is a band-aid solution. It works and we have test coverage for it
thankfully. Longer term we should move the parser to a fully
state-machine based parser that parses the trigger first then the
action, to avoid these kind of things.
2025-09-16 13:53:16 -07:00
Mitchell Hashimoto
a32d4988f7 config: update theme names in docs (#8655)
They were renamed, see:
https://github.com/mbadolato/iTerm2-Color-Schemes/commits/master/ghostty/Rose%20Pine
2025-09-16 07:01:43 -07:00
Mitchell Hashimoto
b5b4b1be72 ci: no dmg to notarize for debug builds 2025-09-16 06:50:40 -07:00
Mitchell Hashimoto
07243789be docs: add lacking version information (#8653)
According to the release note
(https://ghostty.org/docs/install/release-notes/1-2-0#quick-terminal-size),
`quick-terminal-size` option is available since 1.2.0.
At first, I opened a PR in ghostty-org/website
(https://github.com/ghostty-org/website/pull/370). Then the bot
commented that the part was auto-generated content, so I created this
PR.
2025-09-16 06:05:19 -07:00
Jon Parise
ed0d1b8371 Bash shell-integration mark ssh wrapper as a function (#8647) 2025-09-16 07:55:49 -04:00
Simon Olofsson
fd03a146ba config: update theme names in docs
They were renamed, see: https://github.com/mbadolato/iTerm2-Color-Schemes/commits/master/ghostty/Rose%20Pine
2025-09-16 10:37:24 +02:00
カワリミ人形
a92a237b80 docs: add lacking version information
`quick-terminal-size` option is available since 1.2.0
2025-09-16 16:13:56 +09:00
Nilton Perim Neto
79f8ea07a1 Some portuguese translation updates (#8633)
Added some prepositions not previously added and
changed a word to be more accurate to the portuguese meaning

---------

Signed-off-by: Nilton Perim Neto <niltonperimneto@gmail.com>
2025-09-16 04:13:12 +00:00
rhodes-b
1397c76243 mark ssh shell-integration wrapper as a function this matches other features + fixes a case where users alias to some other command 2025-09-15 21:49:48 -05:00
Mitchell Hashimoto
0646cf8c1e Docs: add undo-timeout configuration setting name (#8639)
The action to undo commands had the configuration option missing

Related to: https://github.com/ghostty-org/website/pull/367
2025-09-15 14:02:14 -07:00
dmunozv04
c6143a1539 Docs: add undo-timeout configuration setting name 2025-09-15 22:55:01 +02:00
Mitchell Hashimoto
0e9d052e68 Pass config to splits in NewTerminalConfig (#8638)
Config contains the command, working directory, and environment
variables intended to be passed to the new split, but it looks like we
forgot to include it as an argument in this branch.

Discussion: https://github.com/ghostty-org/ghostty/discussions/8637
2025-09-15 13:18:40 -07:00
Caleb Hearth
ac9f3b88aa Pass config to splits in NewTerminalConfig
Config contains the command, working directory, and environment
variables intended to be passed to the new split, but it looks like we
forgot to include it as an argument in this branch.

Discussion: https://github.com/ghostty-org/ghostty/discussions/8637
2025-09-15 13:16:18 -06:00
Mitchell Hashimoto
8b00bd430d bump the version for development (#8635) 2025-09-15 11:04:57 -07:00
Mitchell Hashimoto
1201bc27d2 bump the version for development 2025-09-15 11:01:14 -07:00
Jacob Sandlund
4d37853f6c benchmark sources 2025-09-11 10:30:01 -04:00
Jacob Sandlund
8a40c1f59f Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-10 10:01:06 -04:00
Jacob Sandlund
cffa52e658 changes after benchmarking 2025-09-09 11:38:10 -04:00
Jacob Sandlund
7a1865080f Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-09 08:19:53 -04:00
Jacob Sandlund
2a3629fe21 Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-08 08:31:34 -04:00
Jacob Sandlund
0af7dc703d Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-06 15:53:07 -04:00
Jacob Sandlund
9ed2385b48 Merge main 2025-09-06 15:52:35 -04:00
Jacob Sandlund
b0db51c45e fast getX(.is_symbol) 2025-09-06 15:01:29 -04:00
Jacob Sandlund
c3994347c0 doNotOptimizeAway 2025-09-06 14:55:21 -04:00
Jacob Sandlund
f86a3a9b50 Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-06 14:31:41 -04:00
Jacob Sandlund
2af08bdbe3 trying a bunch of things to get performance to match 2025-09-06 10:42:02 -04:00
Jacob Sandlund
c67f51f3ee Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-09-01 01:34:03 -04:00
Jacob Sandlund
6d02da0317 nix and flatpak 2025-08-30 18:20:06 -04:00
Jacob Sandlund
c7fa1d8381 using uucode for the graphemeBreak in shaper/web_canvas.zig 2025-08-23 14:33:11 -04:00
Jacob Sandlund
39ecfe9211 Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-08-23 09:16:11 -04:00
Jacob Sandlund
3c61aaca2a attempting to use uucode from uucode.x 2025-08-23 09:16:01 -04:00
Jacob Sandlund
0444c614da update for new grapheme_break 2025-08-21 22:29:34 -04:00
Jacob Sandlund
90832d89b3 Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-08-21 21:13:40 -04:00
Jacob Sandlund
8f0785e90a is_emoji_presentation 2025-08-17 21:33:37 -04:00
Jacob Sandlund
0b7ab006e9 nix and flatpak updates 2025-08-17 21:27:59 -04:00
Jacob Sandlund
e84d8535f5 removing all ziglyph imports (aside from unicode/grapheme.zig) 2025-08-17 21:24:27 -04:00
Jacob Sandlund
1abc9b5e41 array 2025-08-17 19:05:40 -04:00
Jacob Sandlund
0979ea3371 Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-08-17 18:41:21 -04:00
Jacob Sandlund
341137ce2e case folding 2025-08-13 09:56:05 -04:00
Jacob Sandlund
f5a036a6a0 update after refactor (string field config, etc) 2025-08-12 09:43:12 -04:00
Jacob Sandlund
563cfb94ba Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-08-12 09:38:19 -04:00
Jacob Sandlund
7e429d73d6 block 2025-08-06 00:06:27 -04:00
Jacob Sandlund
0c393299b0 using just get 2025-08-05 23:59:30 -04:00
Jacob Sandlund
8dec520b41 testing uucode.x 2025-08-04 10:02:41 -04:00
Jacob Sandlund
e5bbc9e83d Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-08-04 10:00:33 -04:00
Jacob Sandlund
807d128e20 Use table_0_fields build option 2025-07-30 11:22:35 -04:00
Jacob Sandlund
1c445fae9b Merge remote-tracking branch 'upstream/main' into jacob/uucode 2025-07-28 08:18:57 -04:00
Jacob Sandlund
16c7ebad1d Add TODO about configuration 2025-07-27 18:48:39 -04:00
Jacob Sandlund
fb2cab5aee Using uucode in a few places where it's easy. 2025-07-27 18:27:46 -04:00
Jacob Sandlund
70bc29f815 Initial testing including uucode 2025-07-27 16:30:55 -04:00
171 changed files with 4653 additions and 7086 deletions

View File

@@ -36,13 +36,13 @@ jobs:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- name: Setup Nix
uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16

View File

@@ -83,13 +83,13 @@ jobs:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable

View File

@@ -34,7 +34,7 @@ jobs:
with:
# Important so that build number generation works
fetch-depth: 0
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -163,12 +163,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -579,7 +579,6 @@ jobs:
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
# validated by macOS even when an internet connection is not available.
echo "Attach staple"
xcrun stapler staple "Ghostty.dmg"
xcrun stapler staple "macos/build/Release/Ghostty.app"
# Zip up the app

View File

@@ -38,7 +38,7 @@ jobs:
tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix

View File

@@ -12,8 +12,10 @@ jobs:
needs:
- build-bench
- build-dist
- build-examples
- build-flatpak
- build-freebsd
- build-libghostty-vt
- build-linux
- build-linux-libghostty
- build-nix
@@ -22,8 +24,10 @@ jobs:
- build-snap
- build-windows
- test
- test-simd
- test-gtk
- test-sentry-linux
- test-i18n
- test-macos
- pinact
- prettier
@@ -69,14 +73,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -87,6 +91,42 @@ jobs:
- name: Build Benchmarks
run: nix develop -c zig build -Demit-bench
build-examples:
strategy:
fail-fast: false
matrix:
dir: [c-vt, zig-vt]
name: Example ${{ matrix.dir }}
runs-on: namespace-profile-ghostty-sm
needs: test
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Build Example
run: |
cd example/${{ matrix.dir }}
nix develop -c zig build
build-flatpak:
strategy:
fail-fast: false
@@ -100,14 +140,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -134,14 +174,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -155,6 +195,48 @@ jobs:
zig build \
-Dsnap
build-libghostty-vt:
strategy:
matrix:
target:
[
aarch64-macos,
x86_64-macos,
aarch64-linux,
x86_64-linux,
x86_64-windows,
]
runs-on: namespace-profile-ghostty-sm
needs: test
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Build
run: |
nix develop -c zig build lib-vt \
-Dtarget=${{ matrix.target }} \
-Dsimd=false
build-linux:
strategy:
fail-fast: false
@@ -170,14 +252,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -199,14 +281,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -232,14 +314,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -278,14 +360,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -490,14 +572,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -532,14 +614,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -564,6 +646,41 @@ jobs:
-Dgtk-x11=${{ matrix.x11 }} \
-Dgtk-wayland=${{ matrix.wayland }}
test-simd:
strategy:
fail-fast: false
matrix:
simd: ["true", "false"]
name: Build -Dsimd=${{ matrix.simd }}
runs-on: namespace-profile-ghostty-sm
needs: test
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Test
run: |
nix develop -c zig build test -Dsimd=${{ matrix.simd }}
test-sentry-linux:
strategy:
fail-fast: false
@@ -580,14 +697,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -628,6 +745,41 @@ jobs:
- name: test
run: nix develop -c zig build test --system ${{ steps.deps.outputs.deps }}
test-i18n:
strategy:
fail-fast: false
matrix:
i18n: ["true", "false"]
name: Build -Di18n=${{ matrix.simd }}
runs-on: namespace-profile-ghostty-sm
needs: test
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Test
run: |
nix develop -c zig build -Di18n=${{ matrix.i18n }}
zig-fmt:
if: github.repository == 'ghostty-org/ghostty'
runs-on: namespace-profile-ghostty-xsm
@@ -638,12 +790,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -666,12 +818,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -693,12 +845,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -720,12 +872,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -747,12 +899,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -774,12 +926,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -808,12 +960,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -835,12 +987,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -870,14 +1022,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -892,6 +1044,7 @@ jobs:
test-debian-13:
name: Test build on Debian 13
runs-on: namespace-profile-ghostty-sm
timeout-minutes: 10
needs: [test, build-dist]
steps:
- name: Install and configure Namespace CLI
@@ -957,14 +1110,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -999,7 +1152,7 @@ jobs:
sudo systemctl start ssh
- name: Set up FreeBSD VM
uses: vmactions/freebsd-vm@05856381fab64eeee9b038a0818f6cec649ca17a # v1.2.3
uses: vmactions/freebsd-vm@487ce35b96fae3e60d45b521735f5aa436ecfade # v1.2.4
with:
release: ${{ matrix.release }}
copyback: false

View File

@@ -22,14 +22,14 @@ jobs:
fetch-depth: 0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- name: Setup Nix
uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16

28
Doxyfile Normal file
View File

@@ -0,0 +1,28 @@
# Doxyfile 1.13.2
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "libghostty"
INPUT = include/ghostty/vt.h
INPUT_ENCODING = UTF-8
RECURSIVE = NO
#---------------------------------------------------------------------------
# HTML Output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = zig-out/share/ghostty/doc/libghostty
#---------------------------------------------------------------------------
# Man Output
#---------------------------------------------------------------------------
GENERATE_MAN = YES
MAN_OUTPUT = zig-out/share/man
MAN_EXTENSION = .3
#---------------------------------------------------------------------------
# Other Output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO

View File

@@ -16,20 +16,36 @@ pub fn build(b: *std.Build) !void {
// want to know what options are available, you can run `--help` or
// you can read `src/build/Config.zig`.
const config = try buildpkg.Config.init(b);
const test_filter = b.option(
[]const u8,
const test_filters = b.option(
[][]const u8,
"test-filter",
"Filter for test. Only applies to Zig tests.",
) orelse &[0][]const u8{};
// Ghostty dependencies used by many artifacts.
const deps = try buildpkg.SharedDeps.init(b, &config);
// The modules exported for Zig consumers of libghostty. If you're
// writing a Zig program that uses libghostty, read this file.
const mod = try buildpkg.GhosttyZig.init(
b,
&config,
&deps,
);
// All our steps which we'll hook up later. The steps are shown
// up here just so that they are more self-documenting.
const libvt_step = b.step("lib-vt", "Build libghostty-vt");
const run_step = b.step("run", "Run the app");
const run_valgrind_step = b.step(
"run-valgrind",
"Run the app under valgrind",
);
const test_step = b.step("test", "Run tests");
const test_lib_vt_step = b.step(
"test-lib-vt",
"Run libghostty-vt tests",
);
const test_valgrind_step = b.step(
"test-valgrind",
"Run tests under valgrind",
@@ -43,10 +59,6 @@ pub fn build(b: *std.Build) !void {
const resources = try buildpkg.GhosttyResources.init(b, &config);
const i18n = if (config.i18n) try buildpkg.GhosttyI18n.init(b, &config) else null;
// Ghostty dependencies used by many artifacts.
const deps = try buildpkg.SharedDeps.init(b, &config);
if (config.emit_helpgen) deps.help_strings.install();
// Ghostty executable, the actual runnable Ghostty program.
const exe = try buildpkg.GhosttyExe.init(b, &config, &deps);
@@ -79,7 +91,7 @@ pub fn build(b: *std.Build) !void {
check_step.dependOn(dist.install_step);
}
// libghostty
// libghostty (internal, big)
const libghostty_shared = try buildpkg.GhosttyLib.initShared(
b,
&deps,
@@ -89,6 +101,17 @@ pub fn build(b: *std.Build) !void {
&deps,
);
// libghostty-vt
const libghostty_vt_shared = try buildpkg.GhosttyLibVt.initShared(
b,
&mod,
);
libghostty_vt_shared.install(libvt_step);
libghostty_vt_shared.install(b.getInstallStep());
// Helpgen
if (config.emit_helpgen) deps.help_strings.install();
// Runtime "none" is libghostty, anything else is an executable.
if (config.app_runtime != .none) {
if (config.emit_exe) {
@@ -191,7 +214,7 @@ pub fn build(b: *std.Build) !void {
run_step.dependOn(&macos_app_native_only.open.step);
// If we have no test filters, install the tests too
if (test_filter == null) {
if (test_filters.len == 0) {
macos_app_native_only.addTestStepDependencies(test_step);
}
}
@@ -222,11 +245,33 @@ pub fn build(b: *std.Build) !void {
run_valgrind_step.dependOn(&run_cmd.step);
}
// Zig module tests
{
const mod_vt_test = b.addTest(.{
.root_module = mod.vt,
.target = config.target,
.optimize = config.optimize,
.filters = test_filters,
});
const mod_vt_test_run = b.addRunArtifact(mod_vt_test);
test_lib_vt_step.dependOn(&mod_vt_test_run.step);
const mod_vt_c_test = b.addTest(.{
.root_module = mod.vt_c,
.target = config.target,
.optimize = config.optimize,
.filters = test_filters,
});
const mod_vt_c_test_run = b.addRunArtifact(mod_vt_c_test);
test_lib_vt_step.dependOn(&mod_vt_c_test_run.step);
}
// Tests
{
// Full unit tests
const test_exe = b.addTest(.{
.name = "ghostty-test",
.filters = if (test_filter) |v| &.{v} else &.{},
.filters = test_filters,
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = config.baselineTarget(),
@@ -236,7 +281,6 @@ pub fn build(b: *std.Build) !void {
.unwind_tables = .sync,
}),
});
if (config.emit_test_exe) b.installArtifact(test_exe);
_ = try deps.add(test_exe);
@@ -244,6 +288,9 @@ pub fn build(b: *std.Build) !void {
const test_run = b.addRunArtifact(test_exe);
test_step.dependOn(&test_run.step);
// Normal tests always test our libghostty modules
test_step.dependOn(test_lib_vt_step);
// Valgrind test running
const valgrind_run = b.addSystemCommand(&.{
"valgrind",

View File

@@ -1,6 +1,6 @@
.{
.name = .ghostty,
.version = "1.2.0",
.version = "1.2.1",
.paths = .{""},
.fingerprint = 0x64407a2a0b4147e5,
.minimum_zig_version = "0.14.1",
@@ -37,15 +37,15 @@
.hash = "N-V-__8AAB9YCQBaZtQjJZVndk-g_GDIK-NTZcIa63bFp9yZ",
.lazy = true,
},
.ziglyph = .{
.url = "https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz",
.hash = "ziglyph-0.11.2-AAAAAHPtHwB4Mbzn1KvOV7Wpjo82NYEc_v0WC8oCLrkf",
.lazy = true,
.uucode = .{
.url = "https://github.com/jacobsandlund/uucode/archive/190706c6b56f0842d29778007f74f7d3d1335fc5.tar.gz",
.hash = "uucode-0.1.0-ZZjBPpAFQABNCvd9cVPBg4I7233Ays-NWfWphPNqGbyE",
},
.zig_wayland = .{
// codeberg ifreund/zig-wayland
.url = "https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz",
.hash = "wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy",
.lazy = true,
},
.zf = .{
// natecraddock/zf
@@ -56,8 +56,8 @@
.gobject = .{
// https://github.com/jcollie/ghostty-gobject based on zig_gobject
// Temporary until we generate them at build time automatically.
.url = "https://github.com/jcollie/ghostty-gobject/releases/download/0.15.1-2025-09-04-48-1/ghostty-gobject-0.15.1-2025-09-04-48-1.tar.zst",
.hash = "gobject-0.3.0-Skun7ET3nQAc0LzvO0NAvTiGGnmkF36cnmbeCAF6MB7Z",
.url = "https://github.com/ghostty-org/zig-gobject/releases/download/2025-09-20-20-1/ghostty-gobject-2025-09-20-20-1.tar.zst",
.hash = "gobject-0.3.0-Skun7ET3nQCqJhDL0KnF_X7M4L7o7JePsJBbrYpEr7UV",
.lazy = true,
},
@@ -104,17 +104,19 @@
.jetbrains_mono = .{
.url = "https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz",
.hash = "N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x",
.lazy = true,
},
.nerd_fonts_symbols_only = .{
.url = "https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz",
.hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO26s",
.lazy = true,
},
// Other
.apple_sdk = .{ .path = "./pkg/apple-sdk" },
.iterm2_themes = .{
.url = "https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz",
.hash = "N-V-__8AANodAwDnyHwhlOv5cVRn2rx_dTvija-wy5YtTw1B",
.url = "https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20250922-150534-d28055b/ghostty-themes.tgz",
.hash = "N-V-__8AACEnAwCkyrJ_XqdomYlR8bpuh0l8WDidEz-BAzIv",
.lazy = true,
},
},

22
build.zig.zon.json generated
View File

@@ -24,10 +24,10 @@
"url": "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz",
"hash": "sha256-FKLtu1Ccs+UamlPj9eQ12/WXFgS0uDPmPmB26MCpl7U="
},
"gobject-0.3.0-Skun7ET3nQAc0LzvO0NAvTiGGnmkF36cnmbeCAF6MB7Z": {
"gobject-0.3.0-Skun7ET3nQCqJhDL0KnF_X7M4L7o7JePsJBbrYpEr7UV": {
"name": "gobject",
"url": "https://github.com/jcollie/ghostty-gobject/releases/download/0.15.1-2025-09-04-48-1/ghostty-gobject-0.15.1-2025-09-04-48-1.tar.zst",
"hash": "sha256-h6aKUerGlX2ATVEeoN03eWaqDqvUmKdedgpxrSoHvrY="
"url": "https://github.com/ghostty-org/zig-gobject/releases/download/2025-09-20-20-1/ghostty-gobject-2025-09-20-20-1.tar.zst",
"hash": "sha256-SXiqGm81aUn6yq1wFXgNTAULdKOHS/Rzkp5OgNkkcXo="
},
"N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr": {
"name": "gtk4_layer_shell",
@@ -49,10 +49,10 @@
"url": "https://deps.files.ghostty.org/imgui-1220bc6b9daceaf7c8c60f3c3998058045ba0c5c5f48ae255ff97776d9cd8bfc6402.tar.gz",
"hash": "sha256-oF/QHgTPEat4Hig4fGIdLkIPHmBEyOJ6JeYD6pnveGA="
},
"N-V-__8AANodAwDnyHwhlOv5cVRn2rx_dTvija-wy5YtTw1B": {
"N-V-__8AACEnAwCkyrJ_XqdomYlR8bpuh0l8WDidEz-BAzIv": {
"name": "iterm2_themes",
"url": "https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz",
"hash": "sha256-6rKNFpaUvSbvNZ0/+u0h4I/RRaV5V7xIPQ9y7eNVbCA="
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20250922-150534-d28055b/ghostty-themes.tgz",
"hash": "sha256-mdhUxAAqKxRRXwED2laabUo9ZZqZa/MZAsO0+Y9L7uQ="
},
"N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x": {
"name": "jetbrains_mono",
@@ -109,6 +109,11 @@
"url": "https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz",
"hash": "sha256-/8ZooxDndgfTk/PBizJxXyI9oerExNbgV5oR345rWc8="
},
"uucode-0.1.0-ZZjBPpAFQABNCvd9cVPBg4I7233Ays-NWfWphPNqGbyE": {
"name": "uucode",
"url": "https://github.com/jacobsandlund/uucode/archive/190706c6b56f0842d29778007f74f7d3d1335fc5.tar.gz",
"hash": "sha256-iq9Oyns5e5Tnz2BKPPPTuyJ03BN4bK0dsmSPE1s0wig="
},
"vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn": {
"name": "vaxis",
"url": "git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23",
@@ -164,11 +169,6 @@
"url": "git+https://github.com/TUSF/zigimg#31268548fe3276c0e95f318a6c0d2ab10565b58d",
"hash": "sha256-oblfr2FIzuqq0FLo/RrzCwUX1NJJuT53EwD3nP3KwN0="
},
"ziglyph-0.11.2-AAAAAHPtHwB4Mbzn1KvOV7Wpjo82NYEc_v0WC8oCLrkf": {
"name": "ziglyph",
"url": "https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz",
"hash": "sha256-cse98+Ft8QUjX+P88yyYfaxJOJGQ9M7Ymw7jFxDz89k="
},
"N-V-__8AAB0eQwD-0MdOEBmz7intriBReIsIDNlukNVoNu6o": {
"name": "zlib",
"url": "https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz",

28
build.zig.zon.nix generated
View File

@@ -123,11 +123,11 @@ in
};
}
{
name = "gobject-0.3.0-Skun7ET3nQAc0LzvO0NAvTiGGnmkF36cnmbeCAF6MB7Z";
name = "gobject-0.3.0-Skun7ET3nQCqJhDL0KnF_X7M4L7o7JePsJBbrYpEr7UV";
path = fetchZigArtifact {
name = "gobject";
url = "https://github.com/jcollie/ghostty-gobject/releases/download/0.15.1-2025-09-04-48-1/ghostty-gobject-0.15.1-2025-09-04-48-1.tar.zst";
hash = "sha256-h6aKUerGlX2ATVEeoN03eWaqDqvUmKdedgpxrSoHvrY=";
url = "https://github.com/ghostty-org/zig-gobject/releases/download/2025-09-20-20-1/ghostty-gobject-2025-09-20-20-1.tar.zst";
hash = "sha256-SXiqGm81aUn6yq1wFXgNTAULdKOHS/Rzkp5OgNkkcXo=";
};
}
{
@@ -163,11 +163,11 @@ in
};
}
{
name = "N-V-__8AANodAwDnyHwhlOv5cVRn2rx_dTvija-wy5YtTw1B";
name = "N-V-__8AACEnAwCkyrJ_XqdomYlR8bpuh0l8WDidEz-BAzIv";
path = fetchZigArtifact {
name = "iterm2_themes";
url = "https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz";
hash = "sha256-6rKNFpaUvSbvNZ0/+u0h4I/RRaV5V7xIPQ9y7eNVbCA=";
url = "https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20250922-150534-d28055b/ghostty-themes.tgz";
hash = "sha256-mdhUxAAqKxRRXwED2laabUo9ZZqZa/MZAsO0+Y9L7uQ=";
};
}
{
@@ -258,6 +258,14 @@ in
hash = "sha256-/8ZooxDndgfTk/PBizJxXyI9oerExNbgV5oR345rWc8=";
};
}
{
name = "uucode-0.1.0-ZZjBPpAFQABNCvd9cVPBg4I7233Ays-NWfWphPNqGbyE";
path = fetchZigArtifact {
name = "uucode";
url = "https://github.com/jacobsandlund/uucode/archive/190706c6b56f0842d29778007f74f7d3d1335fc5.tar.gz";
hash = "sha256-iq9Oyns5e5Tnz2BKPPPTuyJ03BN4bK0dsmSPE1s0wig=";
};
}
{
name = "vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn";
path = fetchZigArtifact {
@@ -346,14 +354,6 @@ in
hash = "sha256-oblfr2FIzuqq0FLo/RrzCwUX1NJJuT53EwD3nP3KwN0=";
};
}
{
name = "ziglyph-0.11.2-AAAAAHPtHwB4Mbzn1KvOV7Wpjo82NYEc_v0WC8oCLrkf";
path = fetchZigArtifact {
name = "ziglyph";
url = "https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz";
hash = "sha256-cse98+Ft8QUjX+P88yyYfaxJOJGQ9M7Ymw7jFxDz89k=";
};
}
{
name = "N-V-__8AAB0eQwD-0MdOEBmz7intriBReIsIDNlukNVoNu6o";
path = fetchZigArtifact {

6
build.zig.zon.txt generated
View File

@@ -8,7 +8,6 @@ https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918
https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz
https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz
https://deps.files.ghostty.org/gettext-0.24.tar.gz
https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz
https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz
https://deps.files.ghostty.org/gtk4-layer-shell-1.1.0.tar.gz
https://deps.files.ghostty.org/harfbuzz-11.0.0.tar.xz
@@ -26,9 +25,10 @@ https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.
https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz
https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz
https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz
https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
https://github.com/jcollie/ghostty-gobject/releases/download/0.15.1-2025-09-04-48-1/ghostty-gobject-0.15.1-2025-09-04-48-1.tar.zst
https://github.com/ghostty-org/zig-gobject/releases/download/2025-09-20-20-1/ghostty-gobject-2025-09-20-20-1.tar.zst
https://github.com/jacobsandlund/uucode/archive/190706c6b56f0842d29778007f74f7d3d1335fc5.tar.gz
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20250922-150534-d28055b/ghostty-themes.tgz
https://github.com/mitchellh/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz
https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz
https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz

View File

@@ -1,189 +0,0 @@
import { ZigJS } from "zig-js";
const zjs = new ZigJS();
const importObject = {
module: {},
env: {
memory: new WebAssembly.Memory({
initial: 25,
maximum: 65536,
shared: true,
}),
log: (ptr: number, len: number) => {
const arr = new Uint8ClampedArray(zjs.memory.buffer, ptr, len);
const data = arr.slice();
const str = new TextDecoder("utf-8").decode(data);
console.log(str);
},
},
...zjs.importObject(),
};
const url = new URL("ghostty-wasm.wasm", import.meta.url);
fetch(url.href)
.then((response) => response.arrayBuffer())
.then((bytes) => WebAssembly.instantiate(bytes, importObject))
.then((results) => {
const memory = importObject.env.memory;
const {
malloc,
free,
config_new,
config_free,
config_load_string,
config_finalize,
face_new,
face_free,
face_render_glyph,
face_debug_canvas,
deferred_face_new,
deferred_face_free,
deferred_face_load,
deferred_face_face,
group_new,
group_free,
group_add_face,
group_init_sprite_face,
group_index_for_codepoint,
group_render_glyph,
group_cache_new,
group_cache_free,
group_cache_index_for_codepoint,
group_cache_render_glyph,
group_cache_atlas_grayscale,
group_cache_atlas_color,
atlas_new,
atlas_free,
atlas_debug_canvas,
shaper_new,
shaper_free,
shaper_test,
} = results.instance.exports;
// Give us access to the zjs value for debugging.
globalThis.zjs = zjs;
console.log(zjs);
// Initialize our zig-js memory
zjs.memory = memory;
// Helpers
const makeStr = (str) => {
const utf8 = new TextEncoder().encode(str);
const ptr = malloc(utf8.byteLength);
new Uint8Array(memory.buffer, ptr).set(utf8);
return { ptr: ptr, len: utf8.byteLength };
};
// Create our config
const config = config_new();
const config_str = makeStr("font-family = monospace");
config_load_string(config, config_str.ptr, config_str.len);
config_finalize(config);
free(config_str.ptr);
// Create our atlas
// const atlas = atlas_new(512, 0 /* grayscale */);
// Create some memory for our string
const font_name = makeStr("monospace");
// Initialize our deferred face
// const df = deferred_face_new(font_ptr, font.byteLength, 0 /* text */);
//deferred_face_load(df, 72 /* size */);
//const face = deferred_face_face(df);
// Initialize our font face
//const face = face_new(font_ptr, font.byteLength, 72 /* size in px */);
//free(font_ptr);
// Create our group
const group = group_new(32 /* size */);
group_add_face(
group,
0 /* regular */,
deferred_face_new(font_name.ptr, font_name.len, 0 /* text */),
);
group_add_face(
group,
0 /* regular */,
deferred_face_new(font_name.ptr, font_name.len, 1 /* emoji */),
);
// Initialize our sprite font, without this we just use the browser.
group_init_sprite_face(group);
// Create our group cache
const group_cache = group_cache_new(group);
// Render a glyph
// for (let i = 33; i <= 126; i++) {
// const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
// group_cache_render_glyph(group_cache, font_idx, i, 0);
// //face_render_glyph(face, atlas, i);
// }
//
// const emoji = ["🐏","🌞","🌚","🍱","💿","🐈","📃","📀","🕡","🙃"];
// for (let i = 0; i < emoji.length; i++) {
// const cp = emoji[i].codePointAt(0);
// const font_idx = group_cache_index_for_codepoint(group_cache, cp, 0, -1 /* best choice */);
// group_cache_render_glyph(group_cache, font_idx, cp, 0);
// }
for (let i = 0x2500; i <= 0x257f; i++) {
const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
group_cache_render_glyph(group_cache, font_idx, i, 0);
}
for (let i = 0x2580; i <= 0x259f; i++) {
const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
group_cache_render_glyph(group_cache, font_idx, i, 0);
}
for (let i = 0x2800; i <= 0x28ff; i++) {
const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
group_cache_render_glyph(group_cache, font_idx, i, 0);
}
for (let i = 0x1fb00; i <= 0x1fb3b; i++) {
const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
group_cache_render_glyph(group_cache, font_idx, i, 0);
}
for (let i = 0x1fb3c; i <= 0x1fb6b; i++) {
const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
group_cache_render_glyph(group_cache, font_idx, i, 0);
}
//face_render_glyph(face, atlas, "橋".codePointAt(0));
//face_render_glyph(face, atlas, "p".codePointAt(0));
// Debug our canvas
//face_debug_canvas(face);
// Let's try shaping
const shaper = shaper_new(120);
//const input = makeStr("hello🐏");
const input = makeStr("hello🐏👍🏽");
shaper_test(shaper, group_cache, input.ptr, input.len);
const cp = 1114112;
const font_idx = group_cache_index_for_codepoint(
group_cache,
cp,
0,
-1 /* best choice */,
);
group_cache_render_glyph(group_cache, font_idx, cp, -1);
// Debug our atlas canvas
{
const atlas = group_cache_atlas_grayscale(group_cache);
const id = atlas_debug_canvas(atlas);
document.getElementById("atlas-canvas").append(zjs.deleteValue(id));
}
{
const atlas = group_cache_atlas_color(group_cache);
const id = atlas_debug_canvas(atlas);
document.getElementById("atlas-color-canvas").append(zjs.deleteValue(id));
}
//face_free(face);
});

17
example/c-vt/README.md Normal file
View File

@@ -0,0 +1,17 @@
# Example: `ghostty-vt` C Program
This contains a simple example of how to use the `ghostty-vt` C library
with a C program.
This uses a `build.zig` and `Zig` to build the C program so that we
can reuse a lot of our build logic and depend directly on our source
tree, but Ghostty emits a standard C library that can be used with any
C tooling.
## Usage
Run the program:
```shell-session
zig build run
```

42
example/c-vt/build.zig Normal file
View File

@@ -0,0 +1,42 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const exe_mod = b.createModule(.{
.target = target,
.optimize = optimize,
});
exe_mod.addCSourceFiles(.{
.root = b.path("src"),
.files = &.{"main.c"},
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.linkLibrary(dep.artifact("ghostty-vt"));
}
// Exe
const exe = b.addExecutable(.{
.name = "c_vt",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
}

View File

@@ -0,0 +1,24 @@
.{
.name = .c_vt,
.version = "0.0.0",
.fingerprint = 0x413a8529b1255f9a,
.minimum_zig_version = "0.14.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

36
example/c-vt/src/main.c Normal file
View File

@@ -0,0 +1,36 @@
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
int main() {
GhosttyOscParser parser;
if (ghostty_osc_new(NULL, &parser) != GHOSTTY_SUCCESS) {
return 1;
}
// Setup change window title command to change the title to "hello"
ghostty_osc_next(parser, '0');
ghostty_osc_next(parser, ';');
const char *title = "hello";
for (size_t i = 0; i < strlen(title); i++) {
ghostty_osc_next(parser, title[i]);
}
// End parsing and get command
GhosttyOscCommand command = ghostty_osc_end(parser, 0);
// Get and print command type
GhosttyOscCommandType type = ghostty_osc_command_type(command);
printf("Command type: %d\n", type);
// Extract and print the title
if (ghostty_osc_command_data(command, GHOSTTY_OSC_DATA_CHANGE_WINDOW_TITLE_STR, &title)) {
printf("Extracted title: %s\n", title);
} else {
printf("Failed to extract title\n");
}
ghostty_osc_free(parser);
return 0;
}

View File

@@ -1,15 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Ghostty Example</title>
<script type="module" src="app.ts"></script>
</head>
<body>
<p>Open your console, we are just debugging here.</p>
<p>The current <b>grayscale</b> font atlas is rendered below.</p>
<div><div id="atlas-canvas" style="display: inline-block; border: 1px solid green;"></div></div>
<p>The current <b>color</b> font atlas is rendered below.</p>
<div><div id="atlas-color-canvas" style="display: inline-block; border: 1px solid blue;"></div></div>
</body>
</html>

4436
example/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +0,0 @@
{
"name": "ghostty example",
"version": "0.1.0",
"description": "Example showing ghostty and wasm.",
"source": "index.html",
"browserslist": "> 0.5%, last 2 versions, not dead",
"scripts": {
"start": "parcel",
"build": "parcel build",
"check": "tsc --noEmit"
},
"author": "Mitchell Hashimoto",
"license": "MIT",
"devDependencies": {
"@parcel/transformer-inline-string": "^2.8.0",
"parcel": "^2.8.0",
"typescript": "^4.9.3"
},
"dependencies": {
"zig-js": "file:../vendor/zig-js/js"
}
}

14
example/zig-vt/README.md Normal file
View File

@@ -0,0 +1,14 @@
# Example: `ghostty-vt` Zig Module
This contains a simple example of how to use the `ghostty-vt` Zig module
exported by Ghostty to have access to a production grade terminal emulator.
Requires the Zig version stated in the `build.zig.zon` file.
## Usage
Run the program:
```shell-session
zig build run
```

50
example/zig-vt/build.zig Normal file
View File

@@ -0,0 +1,50 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const run_step = b.step("run", "Run the app");
const test_step = b.step("test", "Run unit tests");
const exe_mod = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
// You'll want to use a lazy dependency here so that ghostty is only
// downloaded if you actually need it.
if (b.lazyDependency("ghostty", .{
// Setting simd to false will force a pure static build that
// doesn't even require libc, but it has a significant performance
// penalty. If your embedding app requires libc anyway, you should
// always keep simd enabled.
// .simd = false,
})) |dep| {
exe_mod.addImport(
"ghostty-vt",
dep.module("ghostty-vt"),
);
}
// Exe
const exe = b.addExecutable(.{
.name = "zig_vt",
.root_module = exe_mod,
});
b.installArtifact(exe);
// Run
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
// Test
const exe_unit_tests = b.addTest(.{
.root_module = exe_mod,
});
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
test_step.dependOn(&run_exe_unit_tests.step);
}

View File

@@ -0,0 +1,24 @@
.{
.name = .zig_vt,
.version = "0.0.0",
.fingerprint = 0x6045575a7a8387e6,
.minimum_zig_version = "0.14.1",
.dependencies = .{
// Ghostty dependency. In reality, you'd probably use a URL-based
// dependency like the one showed (and commented out) below this one.
// We use a path dependency here for simplicity and to ensure our
// examples always test against the source they're bundled with.
.ghostty = .{ .path = "../../" },
// Example of what a URL-based dependency looks like:
// .ghostty = .{
// .url = "https://github.com/ghostty-org/ghostty/archive/COMMIT.tar.gz",
// .hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO36s",
// },
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View File

@@ -0,0 +1,26 @@
const std = @import("std");
const ghostty_vt = @import("ghostty-vt");
pub fn main() !void {
// Use a debug allocator so we get leak checking. You probably want
// to replace this for release builds.
var gpa: std.heap.DebugAllocator(.{}) = .init;
defer _ = gpa.deinit();
const alloc = gpa.allocator();
// Initialize a terminal.
var t: ghostty_vt.Terminal = try .init(alloc, .{
.cols = 6,
.rows = 40,
});
defer t.deinit(alloc);
// Write some text. It'll wrap because this is too long for our
// columns size above (6).
try t.printString("Hello, World!");
// Get the plain string view of the terminal screen.
const str = try t.plainString(alloc);
defer alloc.free(str);
std.debug.print("{s}\n", .{str});
}

18
flake.lock generated
View File

@@ -49,15 +49,15 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1755972213,
"narHash": "sha256-VYK7aDAv8H1enXn1ECRHmGbeY6RqLnNwUJkOwloIsko=",
"rev": "73e96df7cff5783f45e21342a75a1540c4eddce4",
"lastModified": 1758360447,
"narHash": "sha256-XDY3A83bclygHDtesRoaRTafUd80Q30D/Daf9KSG6bs=",
"rev": "8eaee110344796db060382e15d3af0a9fc396e0e",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/unstable-small/nixos-25.11pre850642.73e96df7cff5/nixexprs.tar.xz"
"url": "https://releases.nixos.org/nixos/unstable/nixos-25.11pre864002.8eaee1103447/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
"url": "https://channels.nixos.org/nixos-unstable-small/nixexprs.tar.xz"
"url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"
}
},
"root": {
@@ -115,17 +115,17 @@
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1757167408,
"narHash": "sha256-4XyJ6fmKd9wgJ7vHUQuULYy5ps2gUgkkDk/PrJb2OPY=",
"lastModified": 1758405547,
"narHash": "sha256-WgaDgvIZMPvlZcZrpPMjkaalTBnGF2lTG+62znXctWM=",
"owner": "jcollie",
"repo": "zon2nix",
"rev": "dc78177e2ad28d5a407c9e783ee781bd559d7dd5",
"rev": "bf983aa90ff169372b9fa8c02e57ea75e0b42245",
"type": "github"
},
"original": {
"owner": "jcollie",
"repo": "zon2nix",
"rev": "dc78177e2ad28d5a407c9e783ee781bd559d7dd5",
"rev": "bf983aa90ff169372b9fa8c02e57ea75e0b42245",
"type": "github"
}
}

View File

@@ -24,7 +24,7 @@
};
zon2nix = {
url = "github:jcollie/zon2nix?rev=dc78177e2ad28d5a407c9e783ee781bd559d7dd5";
url = "github:jcollie/zon2nix?rev=bf983aa90ff169372b9fa8c02e57ea75e0b42245";
inputs = {
# Don't override nixpkgs until Zig 0.15 is available in the Nix branch
# we are using for "normal" builds.

View File

@@ -1,6 +1,6 @@
app-id: com.mitchellh.ghostty-debug
runtime: org.gnome.Platform
runtime-version: "48"
runtime-version: "49"
sdk: org.gnome.Sdk
default-branch: tip
command: ghostty

View File

@@ -1,6 +1,6 @@
app-id: com.mitchellh.ghostty
runtime: org.gnome.Platform
runtime-version: "48"
runtime-version: "49"
sdk: org.gnome.Sdk
default-branch: tip
command: ghostty

View File

@@ -30,19 +30,6 @@ modules:
contents: INPUT(libbz2.so)
dest-filename: libbzip2.so
- name: blueprint-compiler
buildsystem: meson
cleanup:
- "*"
sources:
- type: git
url: https://gitlab.gnome.org/jwestman/blueprint-compiler.git
tag: v0.16.0
commit: 04ef0944db56ab01307a29aaa7303df6067cb3c0
x-checker-data:
type: git
tag-pattern: ^v([\d.]+)$
- name: gtk4-layer-shell
buildsystem: meson
sources:

View File

@@ -31,9 +31,9 @@
},
{
"type": "archive",
"url": "https://github.com/jcollie/ghostty-gobject/releases/download/0.15.1-2025-09-04-48-1/ghostty-gobject-0.15.1-2025-09-04-48-1.tar.zst",
"dest": "vendor/p/gobject-0.3.0-Skun7ET3nQAc0LzvO0NAvTiGGnmkF36cnmbeCAF6MB7Z",
"sha256": "87a68a51eac6957d804d511ea0dd377966aa0eabd498a75e760a71ad2a07beb6"
"url": "https://github.com/ghostty-org/zig-gobject/releases/download/2025-09-20-20-1/ghostty-gobject-2025-09-20-20-1.tar.zst",
"dest": "vendor/p/gobject-0.3.0-Skun7ET3nQCqJhDL0KnF_X7M4L7o7JePsJBbrYpEr7UV",
"sha256": "4978aa1a6f356949facaad7015780d4c050b74a3874bf473929e4e80d924717a"
},
{
"type": "archive",
@@ -61,9 +61,9 @@
},
{
"type": "archive",
"url": "https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz",
"dest": "vendor/p/N-V-__8AANodAwDnyHwhlOv5cVRn2rx_dTvija-wy5YtTw1B",
"sha256": "eab28d169694bd26ef359d3ffaed21e08fd145a57957bc483d0f72ede3556c20"
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20250922-150534-d28055b/ghostty-themes.tgz",
"dest": "vendor/p/N-V-__8AACEnAwCkyrJ_XqdomYlR8bpuh0l8WDidEz-BAzIv",
"sha256": "99d854c4002a2b14515f0103da569a6d4a3d659a996bf31902c3b4f98f4beee4"
},
{
"type": "archive",
@@ -131,6 +131,12 @@
"dest": "vendor/p/N-V-__8AAHffAgDU0YQmynL8K35WzkcnMUmBVQHQ0jlcKpjH",
"sha256": "ffc668a310e77607d393f3c18b32715f223da1eac4c4d6e0579a11df8e6b59cf"
},
{
"type": "archive",
"url": "https://github.com/jacobsandlund/uucode/archive/190706c6b56f0842d29778007f74f7d3d1335fc5.tar.gz",
"dest": "vendor/p/uucode-0.1.0-ZZjBPpAFQABNCvd9cVPBg4I7233Ays-NWfWphPNqGbyE",
"sha256": "8aaf4eca7b397b94e7cf604a3cf3d3bb2274dc13786cad1db2648f135b34c228"
},
{
"type": "git",
"url": "https://github.com/rockorager/libvaxis",
@@ -197,12 +203,6 @@
"commit": "31268548fe3276c0e95f318a6c0d2ab10565b58d",
"dest": "vendor/p/zigimg-0.1.0-lly-O6N2EABOxke8dqyzCwhtUCAafqP35zC7wsZ4Ddxj"
},
{
"type": "archive",
"url": "https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz",
"dest": "vendor/p/ziglyph-0.11.2-AAAAAHPtHwB4Mbzn1KvOV7Wpjo82NYEc_v0WC8oCLrkf",
"sha256": "72c7bdf3e16df105235fe3fcf32c987dac49389190f4ced89b0ee31710f3f3d9"
},
{
"type": "archive",
"url": "https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz",

455
include/ghostty/vt.h Normal file
View File

@@ -0,0 +1,455 @@
/**
* @file vt.h
*
* libghostty-vt - Virtual terminal sequence parsing library
*
* This library provides functionality for parsing and handling terminal
* escape sequences as well as maintaining terminal state such as styles,
* cursor position, screen, scrollback, and more.
*
* WARNING: This is an incomplete, work-in-progress API. It is not yet
* stable and is definitely going to change.
*/
/**
* @mainpage libghostty-vt - Virtual Terminal Sequence Parser
*
* libghostty-vt is a C library which implements a modern terminal emulator,
* extracted from the [Ghostty](https://ghostty.org) terminal emulator.
*
* libghostty-vt contains the logic for handling the core parts of a terminal
* emulator: parsing terminal escape sequences and maintaining terminal state.
* It can handle scrollback, line wrapping, reflow on resize, and more.
*
* @warning This library is currently in development and the API is not yet stable.
* Breaking changes are expected in future versions. Use with caution in production code.
*
* @section groups_sec API Reference
*
* The API is organized into the following groups:
* - @ref osc "OSC Parser" - Parse OSC (Operating System Command) sequences
* - @ref allocator "Memory Management" - Memory management and custom allocators
*
*/
#ifndef GHOSTTY_VT_H
#define GHOSTTY_VT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
//-------------------------------------------------------------------
// Types
/**
* Opaque handle to an OSC parser instance.
*
* This handle represents an OSC (Operating System Command) parser that can
* be used to parse the contents of OSC sequences. This isn't a full VT
* parser; it is only the OSC parser component. This is useful if you have
* a parser already and want to only extract and handle OSC sequences.
*
* @ingroup osc
*/
typedef struct GhosttyOscParser *GhosttyOscParser;
/**
* Opaque handle to a single OSC command.
*
* This handle represents a parsed OSC (Operating System Command) command.
* The command can be queried for its type and associated data using
* `ghostty_osc_command_type` and `ghostty_osc_command_data`.
*
* @ingroup osc
*/
typedef struct GhosttyOscCommand *GhosttyOscCommand;
/**
* Result codes for libghostty-vt operations.
*/
typedef enum {
/** Operation completed successfully */
GHOSTTY_SUCCESS = 0,
/** Operation failed due to failed allocation */
GHOSTTY_OUT_OF_MEMORY = -1,
} GhosttyResult;
/**
* OSC command types.
*
* @ingroup osc
*/
typedef enum {
GHOSTTY_OSC_COMMAND_INVALID = 0,
GHOSTTY_OSC_COMMAND_CHANGE_WINDOW_TITLE = 1,
GHOSTTY_OSC_COMMAND_CHANGE_WINDOW_ICON = 2,
GHOSTTY_OSC_COMMAND_PROMPT_START = 3,
GHOSTTY_OSC_COMMAND_PROMPT_END = 4,
GHOSTTY_OSC_COMMAND_END_OF_INPUT = 5,
GHOSTTY_OSC_COMMAND_END_OF_COMMAND = 6,
GHOSTTY_OSC_COMMAND_CLIPBOARD_CONTENTS = 7,
GHOSTTY_OSC_COMMAND_REPORT_PWD = 8,
GHOSTTY_OSC_COMMAND_MOUSE_SHAPE = 9,
GHOSTTY_OSC_COMMAND_COLOR_OPERATION = 10,
GHOSTTY_OSC_COMMAND_KITTY_COLOR_PROTOCOL = 11,
GHOSTTY_OSC_COMMAND_SHOW_DESKTOP_NOTIFICATION = 12,
GHOSTTY_OSC_COMMAND_HYPERLINK_START = 13,
GHOSTTY_OSC_COMMAND_HYPERLINK_END = 14,
GHOSTTY_OSC_COMMAND_CONEMU_SLEEP = 15,
GHOSTTY_OSC_COMMAND_CONEMU_SHOW_MESSAGE_BOX = 16,
GHOSTTY_OSC_COMMAND_CONEMU_CHANGE_TAB_TITLE = 17,
GHOSTTY_OSC_COMMAND_CONEMU_PROGRESS_REPORT = 18,
GHOSTTY_OSC_COMMAND_CONEMU_WAIT_INPUT = 19,
GHOSTTY_OSC_COMMAND_CONEMU_GUIMACRO = 20,
} GhosttyOscCommandType;
/**
* OSC command data types.
*
* These values specify what type of data to extract from an OSC command
* using `ghostty_osc_command_data`.
*
* @ingroup osc
*/
typedef enum {
/** Invalid data type. Never results in any data extraction. */
GHOSTTY_OSC_DATA_INVALID = 0,
/**
* Window title string data.
*
* Valid for: GHOSTTY_OSC_COMMAND_CHANGE_WINDOW_TITLE
*
* Output type: const char ** (pointer to null-terminated string)
*
* Lifetime: Valid until the next call to any ghostty_osc_* function with
* the same parser instance. Memory is owned by the parser.
*/
GHOSTTY_OSC_DATA_CHANGE_WINDOW_TITLE_STR = 1,
} GhosttyOscCommandData;
//-------------------------------------------------------------------
// Allocator Interface
/** @defgroup allocator Memory Management
*
* libghostty-vt does require memory allocation for various operations,
* but is resilient to allocation failures and will gracefully handle
* out-of-memory situations by returning error codes.
*
* The exact memory management semantics are documented in the relevant
* functions and data structures.
*
* libghostty-vt uses explicit memory allocation via an allocator
* interface provided by GhosttyAllocator. The interface is based on the
* [Zig](https://ziglang.org) allocator interface, since this has been
* shown to be a flexible and powerful interface in practice and enables
* a wide variety of allocation strategies.
*
* **For the common case, you can pass NULL as the allocator for any
* function that accepts one,** and libghostty will use a default allocator.
* The default allocator will be libc malloc/free if libc is linked.
* Otherwise, a custom allocator is used (currently Zig's SMP allocator)
* that doesn't require any external dependencies.
*
* ## Basic Usage
*
* For simple use cases, you can ignore this interface entirely by passing NULL
* as the allocator parameter to functions that accept one. This will use the
* default allocator (typically libc malloc/free, if libc is linked, but
* we provide our own default allocator if libc isn't linked).
*
* To use a custom allocator:
* 1. Implement the GhosttyAllocatorVtable function pointers
* 2. Create a GhosttyAllocator struct with your vtable and context
* 3. Pass the allocator to functions that accept one
*
* @{
*/
/**
* Function table for custom memory allocator operations.
*
* This vtable defines the interface for a custom memory allocator. All
* function pointers must be valid and non-NULL.
*
* @ingroup allocator
*
* If you're not going to use a custom allocator, you can ignore all of
* this. All functions that take an allocator pointer allow NULL to use a
* default allocator.
*
* The interface is based on the Zig allocator interface. I'll say up front
* that it is easy to look at this interface and think "wow, this is really
* overcomplicated". The reason for this complexity is well thought out by
* the Zig folks, and it enables a diverse set of allocation strategies
* as shown by the Zig ecosystem. As a consolation, please note that many
* of the arguments are only needed for advanced use cases and can be
* safely ignored in simple implementations. For example, if you look at
* the Zig implementation of the libc allocator in `lib/std/heap.zig`
* (search for CAllocator), you'll see it is very simple.
*
* We chose to align with the Zig allocator interface because:
*
* 1. It is a proven interface that serves a wide variety of use cases
* in the real world via the Zig ecosystem. It's shown to work.
*
* 2. Our core implementation itself is Zig, and this lets us very
* cheaply and easily convert between C and Zig allocators.
*
* NOTE(mitchellh): In the future, we can have default implementations of
* resize/remap and allow those to be null.
*/
typedef struct {
/**
* Return a pointer to `len` bytes with specified `alignment`, or return
* `NULL` indicating the allocation failed.
*
* @param ctx The allocator context
* @param len Number of bytes to allocate
* @param alignment Required alignment for the allocation. Guaranteed to
* be a power of two between 1 and 16 inclusive.
* @param ret_addr First return address of the allocation call stack (0 if not provided)
* @return Pointer to allocated memory, or NULL if allocation failed
*/
void* (*alloc)(void *ctx, size_t len, uint8_t alignment, uintptr_t ret_addr);
/**
* Attempt to expand or shrink memory in place.
*
* `memory_len` must equal the length requested from the most recent
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
* equal the same value that was passed as the `alignment` parameter to
* the original `alloc` call.
*
* `new_len` must be greater than zero.
*
* @param ctx The allocator context
* @param memory Pointer to the memory block to resize
* @param memory_len Current size of the memory block
* @param alignment Alignment (must match original allocation)
* @param new_len New requested size
* @param ret_addr First return address of the allocation call stack (0 if not provided)
* @return true if resize was successful in-place, false if relocation would be required
*/
bool (*resize)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, size_t new_len, uintptr_t ret_addr);
/**
* Attempt to expand or shrink memory, allowing relocation.
*
* `memory_len` must equal the length requested from the most recent
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
* equal the same value that was passed as the `alignment` parameter to
* the original `alloc` call.
*
* A non-`NULL` return value indicates the resize was successful. The
* allocation may have same address, or may have been relocated. In either
* case, the allocation now has size of `new_len`. A `NULL` return value
* indicates that the resize would be equivalent to allocating new memory,
* copying the bytes from the old memory, and then freeing the old memory.
* In such case, it is more efficient for the caller to perform the copy.
*
* `new_len` must be greater than zero.
*
* @param ctx The allocator context
* @param memory Pointer to the memory block to remap
* @param memory_len Current size of the memory block
* @param alignment Alignment (must match original allocation)
* @param new_len New requested size
* @param ret_addr First return address of the allocation call stack (0 if not provided)
* @return Pointer to resized memory (may be relocated), or NULL if manual copy is needed
*/
void* (*remap)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, size_t new_len, uintptr_t ret_addr);
/**
* Free and invalidate a region of memory.
*
* `memory_len` must equal the length requested from the most recent
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
* equal the same value that was passed as the `alignment` parameter to
* the original `alloc` call.
*
* @param ctx The allocator context
* @param memory Pointer to the memory block to free
* @param memory_len Size of the memory block
* @param alignment Alignment (must match original allocation)
* @param ret_addr First return address of the allocation call stack (0 if not provided)
*/
void (*free)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, uintptr_t ret_addr);
} GhosttyAllocatorVtable;
/**
* Custom memory allocator.
*
* For functions that take an allocator pointer, a NULL pointer indicates
* that the default allocator should be used. The default allocator will
* be libc malloc/free if we're linking to libc. If libc isn't linked,
* a custom allocator is used (currently Zig's SMP allocator).
*
* @ingroup allocator
*
* Usage example:
* @code
* GhosttyAllocator allocator = {
* .vtable = &my_allocator_vtable,
* .ctx = my_allocator_state
* };
* @endcode
*/
typedef struct {
/**
* Opaque context pointer passed to all vtable functions.
* This allows the allocator implementation to maintain state
* or reference external resources needed for memory management.
*/
void *ctx;
/**
* Pointer to the allocator's vtable containing function pointers
* for memory operations (alloc, resize, remap, free).
*/
const GhosttyAllocatorVtable *vtable;
} GhosttyAllocator;
/** @} */ // end of allocator group
//-------------------------------------------------------------------
// Functions
/** @defgroup osc OSC Parser
*
* OSC (Operating System Command) sequence parser and command handling.
*
* The parser operates in a streaming fashion, processing input byte-by-byte
* to handle OSC sequences that may arrive in fragments across multiple reads.
* This interface makes it easy to integrate into most environments and avoids
* over-allocating buffers.
*
* ## Basic Usage
*
* 1. Create a parser instance with ghostty_osc_new()
* 2. Feed bytes to the parser using ghostty_osc_next()
* 3. Finalize parsing with ghostty_osc_end() to get the command
* 4. Query command type and extract data using ghostty_osc_command_type()
* and ghostty_osc_command_data()
* 5. Free the parser with ghostty_osc_free() when done
*
* @{
*/
/**
* Create a new OSC parser instance.
*
* Creates a new OSC (Operating System Command) parser using the provided
* allocator. The parser must be freed using ghostty_vt_osc_free() when
* no longer needed.
*
* @param allocator Pointer to the allocator to use for memory management, or NULL to use the default allocator
* @param parser Pointer to store the created parser handle
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*/
GhosttyResult ghostty_osc_new(const GhosttyAllocator *allocator, GhosttyOscParser *parser);
/**
* Free an OSC parser instance.
*
* Releases all resources associated with the OSC parser. After this call,
* the parser handle becomes invalid and must not be used.
*
* @param parser The parser handle to free (may be NULL)
*/
void ghostty_osc_free(GhosttyOscParser parser);
/**
* Reset an OSC parser instance to its initial state.
*
* Resets the parser state, clearing any partially parsed OSC sequences
* and returning the parser to its initial state. This is useful for
* reusing a parser instance or recovering from parse errors.
*
* @param parser The parser handle to reset, must not be null.
*/
void ghostty_osc_reset(GhosttyOscParser parser);
/**
* Parse the next byte in an OSC sequence.
*
* Processes a single byte as part of an OSC sequence. The parser maintains
* internal state to track the progress through the sequence. Call this
* function for each byte in the sequence data.
*
* When finished pumping the parser with bytes, call ghostty_osc_end
* to get the final result.
*
* @param parser The parser handle, must not be null.
* @param byte The next byte to parse
*/
void ghostty_osc_next(GhosttyOscParser parser, uint8_t byte);
/**
* Finalize OSC parsing and retrieve the parsed command.
*
* Call this function after feeding all bytes of an OSC sequence to the parser
* using ghostty_osc_next() with the exception of the terminating character
* (ESC or ST). This function finalizes the parsing process and returns the
* parsed OSC command.
*
* The return value is never NULL. Invalid commands will return a command
* with type GHOSTTY_OSC_COMMAND_INVALID.
*
* The terminator parameter specifies the byte that terminated the OSC sequence
* (typically 0x07 for BEL or 0x5C for ST after ESC). This information is
* preserved in the parsed command so that responses can use the same terminator
* format for better compatibility with the calling program. For commands that
* do not require a response, this parameter is ignored and the resulting
* command will not retain the terminator information.
*
* The returned command handle is valid until the next call to any
* `ghostty_osc_*` function with the same parser instance with the exception
* of command introspection functions such as `ghostty_osc_command_type`.
*
* @param parser The parser handle, must not be null.
* @param terminator The terminating byte of the OSC sequence (0x07 for BEL, 0x5C for ST)
* @return Handle to the parsed OSC command
*/
GhosttyOscCommand ghostty_osc_end(GhosttyOscParser parser, uint8_t terminator);
/**
* Get the type of an OSC command.
*
* Returns the type identifier for the given OSC command. This can be used
* to determine what kind of command was parsed and what data might be
* available from it.
*
* @param command The OSC command handle to query (may be NULL)
* @return The command type, or GHOSTTY_OSC_COMMAND_INVALID if command is NULL
*/
GhosttyOscCommandType ghostty_osc_command_type(GhosttyOscCommand command);
/**
* Extract data from an OSC command.
*
* Extracts typed data from the given OSC command based on the specified
* data type. The output pointer must be of the appropriate type for the
* requested data kind. Valid command types, output types, and memory
* safety information are documented in the `GhosttyOscCommandData` enum.
*
* @param command The OSC command handle to query (may be NULL)
* @param data The type of data to extract
* @param out Pointer to store the extracted data (type depends on data parameter)
* @return true if data extraction was successful, false otherwise
*/
bool ghostty_osc_command_data(GhosttyOscCommand command, GhosttyOscCommandData data, void *out);
/** @} */ // end of osc group
#ifdef __cplusplus
}
#endif
#endif /* GHOSTTY_VT_H */

View File

@@ -10,147 +10,19 @@
29C15B1D2CDC3B2900520DD4 /* bat in Resources */ = {isa = PBXBuildFile; fileRef = 29C15B1C2CDC3B2000520DD4 /* bat */; };
55154BE02B33911F001622DC /* ghostty in Resources */ = {isa = PBXBuildFile; fileRef = 55154BDF2B33911F001622DC /* ghostty */; };
552964E62B34A9B400030505 /* vim in Resources */ = {isa = PBXBuildFile; fileRef = 552964E52B34A9B400030505 /* vim */; };
857F63812A5E64F200CA4815 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 857F63802A5E64F200CA4815 /* MainMenu.xib */; };
9351BE8E3D22937F003B3499 /* nvim in Resources */ = {isa = PBXBuildFile; fileRef = 9351BE8E2D22937F003B3499 /* nvim */; };
A50297352DFA0F3400B4E924 /* Double+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A50297342DFA0F3300B4E924 /* Double+Extension.swift */; };
A505D21D2E1A2FA20018808F /* FileHandle+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A505D21C2E1A2F9E0018808F /* FileHandle+Extension.swift */; };
A505D21F2E1B6DE00018808F /* NSWorkspace+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A505D21E2E1B6DDC0018808F /* NSWorkspace+Extension.swift */; };
A511940F2E050595007258CC /* CloseTerminalIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A511940E2E050590007258CC /* CloseTerminalIntent.swift */; };
A51194112E05A483007258CC /* QuickTerminalIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51194102E05A480007258CC /* QuickTerminalIntent.swift */; };
A51194132E05D006007258CC /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51194122E05D003007258CC /* Optional+Extension.swift */; };
A51194172E05D964007258CC /* PermissionRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51194162E05D95E007258CC /* PermissionRequest.swift */; };
A51194192E05DFC4007258CC /* IntentPermission.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51194182E05DFBB007258CC /* IntentPermission.swift */; };
A514C8D62B54A16400493A16 /* Ghostty.Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = A514C8D52B54A16400493A16 /* Ghostty.Config.swift */; };
A514C8D72B54A16400493A16 /* Ghostty.Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = A514C8D52B54A16400493A16 /* Ghostty.Config.swift */; };
A514C8D82B54DC6800493A16 /* Ghostty.App.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53D0C992B543F3B00305CE6 /* Ghostty.App.swift */; };
A51544FE2DFB111C009E85D8 /* TitlebarTabsTahoeTerminalWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51544FD2DFB1110009E85D8 /* TitlebarTabsTahoeTerminalWindow.swift */; };
A51545002DFB112E009E85D8 /* TerminalTabsTitlebarTahoe.xib in Resources */ = {isa = PBXBuildFile; fileRef = A51544FF2DFB112E009E85D8 /* TerminalTabsTitlebarTahoe.xib */; };
A51B78472AF4B58B00F3EDB9 /* TitlebarTabsVenturaTerminalWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51B78462AF4B58B00F3EDB9 /* TitlebarTabsVenturaTerminalWindow.swift */; };
A51BFC1E2B2FB5CE00E92F16 /* About.xib in Resources */ = {isa = PBXBuildFile; fileRef = A51BFC1D2B2FB5CE00E92F16 /* About.xib */; };
A51BFC202B2FB64F00E92F16 /* AboutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BFC1F2B2FB64F00E92F16 /* AboutController.swift */; };
A51BFC222B2FB6B400E92F16 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BFC212B2FB6B400E92F16 /* AboutView.swift */; };
A51BFC272B30F1B800E92F16 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = A51BFC262B30F1B800E92F16 /* Sparkle */; };
A51BFC2B2B30F6BE00E92F16 /* UpdateDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BFC2A2B30F6BE00E92F16 /* UpdateDelegate.swift */; };
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */; };
A52FFF572CA90484000C6A5B /* QuickTerminalScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A52FFF562CA90481000C6A5B /* QuickTerminalScreen.swift */; };
A52FFF592CAA4FF3000C6A5B /* Fullscreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = A52FFF582CAA4FF1000C6A5B /* Fullscreen.swift */; };
A52FFF5B2CAA54B1000C6A5B /* FullscreenMode+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A52FFF5A2CAA54A8000C6A5B /* FullscreenMode+Extension.swift */; };
A52FFF5D2CAB4D08000C6A5B /* NSScreen+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A52FFF5C2CAB4D05000C6A5B /* NSScreen+Extension.swift */; };
A5333E1C2B5A1CE3008AEFF7 /* CrossKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5333E1B2B5A1CE3008AEFF7 /* CrossKit.swift */; };
A5333E1D2B5A1CE3008AEFF7 /* CrossKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5333E1B2B5A1CE3008AEFF7 /* CrossKit.swift */; };
A5333E202B5A2111008AEFF7 /* SurfaceView_UIKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5333E152B59DE8E008AEFF7 /* SurfaceView_UIKit.swift */; };
A5333E222B5A2128008AEFF7 /* SurfaceView_AppKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5333E212B5A2128008AEFF7 /* SurfaceView_AppKit.swift */; };
A5333E232B5A219A008AEFF7 /* SurfaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BBB29B6FC330055DE60 /* SurfaceView.swift */; };
A5333E242B5A22D9008AEFF7 /* Ghostty.Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A56D58852ACDDB4100508D2C /* Ghostty.Shell.swift */; };
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */; };
A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A535B9D9299C569B0017E2E4 /* ErrorView.swift */; };
A53A297B2DB2E49700B6E02C /* CommandPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53A297A2DB2E49400B6E02C /* CommandPalette.swift */; };
A53A297F2DB4480F00B6E02C /* EventModifiers+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53A297E2DB4480A00B6E02C /* EventModifiers+Extension.swift */; };
A53A29812DB44A6100B6E02C /* KeyboardShortcut+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53A29802DB44A5E00B6E02C /* KeyboardShortcut+Extension.swift */; };
A53A29882DB69D2F00B6E02C /* TerminalCommandPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53A29872DB69D2C00B6E02C /* TerminalCommandPalette.swift */; };
A53A6C032CCC1B7F00943E98 /* Ghostty.Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53A6C022CCC1B7D00943E98 /* Ghostty.Action.swift */; };
A53D0C8E2B53B0EA00305CE6 /* GhosttyKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A5D495A1299BEC7E00DD1313 /* GhosttyKit.xcframework */; };
A53D0C942B53B43700305CE6 /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53D0C932B53B43700305CE6 /* iOSApp.swift */; };
A53D0C952B53B4D800305CE6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; };
A53D0C9B2B543F3B00305CE6 /* Ghostty.App.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53D0C992B543F3B00305CE6 /* Ghostty.App.swift */; };
A53D0C9C2B543F7B00305CE6 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BB729B6F53A0055DE60 /* Package.swift */; };
A546F1142D7B68D7003B11A0 /* locale in Resources */ = {isa = PBXBuildFile; fileRef = A546F1132D7B68D7003B11A0 /* locale */; };
A54B0CE92D0CECD100CBEFF8 /* ColorizedGhosttyIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54B0CE82D0CECD100CBEFF8 /* ColorizedGhosttyIconView.swift */; };
A54B0CEB2D0CFB4C00CBEFF8 /* NSImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54B0CEA2D0CFB4A00CBEFF8 /* NSImage+Extension.swift */; };
A54B0CED2D0CFB7700CBEFF8 /* ColorizedGhosttyIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54B0CEC2D0CFB7300CBEFF8 /* ColorizedGhosttyIcon.swift */; };
A54B0CEF2D0D2E2800CBEFF8 /* ColorizedGhosttyIconImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54B0CEE2D0D2E2400CBEFF8 /* ColorizedGhosttyIconImage.swift */; };
A54D786C2CA7978E001B19B1 /* BaseTerminalController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A54D786B2CA79788001B19B1 /* BaseTerminalController.swift */; };
A553F4062E05E93000257779 /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51194122E05D003007258CC /* Optional+Extension.swift */; };
A553F4072E05E93D00257779 /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A586366A2DF0A98900E04A10 /* Array+Extension.swift */; };
A553F4132E06EB1600257779 /* Ghostty.icon in Resources */ = {isa = PBXBuildFile; fileRef = A553F4122E06EB1600257779 /* Ghostty.icon */; };
A553F4142E06EB1600257779 /* Ghostty.icon in Resources */ = {isa = PBXBuildFile; fileRef = A553F4122E06EB1600257779 /* Ghostty.icon */; };
A5593FDF2DF8D57C00B47B10 /* TerminalWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5593FDE2DF8D57100B47B10 /* TerminalWindow.swift */; };
A5593FE12DF8D74000B47B10 /* HiddenTitlebarTerminalWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5593FE02DF8D73400B47B10 /* HiddenTitlebarTerminalWindow.swift */; };
A5593FE32DF8D78600B47B10 /* TerminalHiddenTitlebar.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5593FE22DF8D78600B47B10 /* TerminalHiddenTitlebar.xib */; };
A5593FE52DF8DE3000B47B10 /* TerminalTabsTitlebarVentura.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5593FE42DF8DE3000B47B10 /* TerminalTabsTitlebarVentura.xib */; };
A5593FE72DF927D200B47B10 /* TransparentTitlebarTerminalWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5593FE62DF927CC00B47B10 /* TransparentTitlebarTerminalWindow.swift */; };
A5593FE92DF927DF00B47B10 /* TerminalTransparentTitlebar.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5593FE82DF927DF00B47B10 /* TerminalTransparentTitlebar.xib */; };
A55B7BB829B6F53A0055DE60 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BB729B6F53A0055DE60 /* Package.swift */; };
A55B7BBC29B6FC330055DE60 /* SurfaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55B7BBB29B6FC330055DE60 /* SurfaceView.swift */; };
A56B880B2A840447007A0E29 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A56B880A2A840447007A0E29 /* Carbon.framework */; };
A56D58862ACDDB4100508D2C /* Ghostty.Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A56D58852ACDDB4100508D2C /* Ghostty.Shell.swift */; };
A56D58892ACDE6CA00508D2C /* ServiceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A56D58882ACDE6CA00508D2C /* ServiceProvider.swift */; };
A571AB1D2A206FCF00248498 /* GhosttyKit.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = A5D495A1299BEC7E00DD1313 /* GhosttyKit.xcframework */; };
A57D79272C9C879B001D522E /* SecureInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A57D79262C9C8798001D522E /* SecureInput.swift */; };
A586167C2B7703CC009BDB1D /* fish in Resources */ = {isa = PBXBuildFile; fileRef = A586167B2B7703CC009BDB1D /* fish */; };
A586365F2DEE6C2300E04A10 /* SplitTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = A586365E2DEE6C2100E04A10 /* SplitTree.swift */; };
A58636662DEF964100E04A10 /* TerminalSplitTreeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58636652DEF963F00E04A10 /* TerminalSplitTreeView.swift */; };
A586366B2DF0A98C00E04A10 /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A586366A2DF0A98900E04A10 /* Array+Extension.swift */; };
A586366F2DF25D8600E04A10 /* Duration+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A586366E2DF25D8300E04A10 /* Duration+Extension.swift */; };
A58636712DF298FB00E04A10 /* ExpiringUndoManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58636702DF298F700E04A10 /* ExpiringUndoManager.swift */; };
A58636732DF4813400E04A10 /* UndoManager+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A58636722DF4813000E04A10 /* UndoManager+Extension.swift */; };
A5874D992DAD751B00E83852 /* CGS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5874D982DAD751A00E83852 /* CGS.swift */; };
A5874D9D2DAD786100E83852 /* NSWindow+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5874D9C2DAD785F00E83852 /* NSWindow+Extension.swift */; };
A59444F729A2ED5200725BBA /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59444F629A2ED5200725BBA /* SettingsView.swift */; };
A59630972AEE163600D64628 /* HostingWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59630962AEE163600D64628 /* HostingWindow.swift */; };
A596309A2AEE1C6400D64628 /* Terminal.xib in Resources */ = {isa = PBXBuildFile; fileRef = A59630992AEE1C6400D64628 /* Terminal.xib */; };
A596309C2AEE1C9E00D64628 /* TerminalController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A596309B2AEE1C9E00D64628 /* TerminalController.swift */; };
A596309E2AEE1D6C00D64628 /* TerminalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A596309D2AEE1D6C00D64628 /* TerminalView.swift */; };
A5985CD72C320C4500C57AD3 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5985CD62C320C4500C57AD3 /* String+Extension.swift */; };
A5985CD82C320C4500C57AD3 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5985CD62C320C4500C57AD3 /* String+Extension.swift */; };
A5985CE62C33060F00C57AD3 /* man in Resources */ = {isa = PBXBuildFile; fileRef = A5985CE52C33060F00C57AD3 /* man */; };
A599CDB02CF103F60049FA26 /* NSAppearance+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A599CDAF2CF103F20049FA26 /* NSAppearance+Extension.swift */; };
A59FB5CF2AE0DB50009128F3 /* InspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */; };
A59FB5D12AE0DEA7009128F3 /* MetalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A59FB5D02AE0DEA7009128F3 /* MetalView.swift */; };
A5A1F8852A489D6800D1E8BC /* terminfo in Resources */ = {isa = PBXBuildFile; fileRef = A5A1F8842A489D6800D1E8BC /* terminfo */; };
A5A2A3CA2D4445E30033CF96 /* Dock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A2A3C92D4445E20033CF96 /* Dock.swift */; };
A5A2A3CC2D444ABB0033CF96 /* NSApplication+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A2A3CB2D444AB80033CF96 /* NSApplication+Extension.swift */; };
A5A6F72A2CC41B8900B232A5 /* AppInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5A6F7292CC41B8700B232A5 /* AppInfo.swift */; };
A5AEB1652D5BE7D000513529 /* LastWindowPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5AEB1642D5BE7BF00513529 /* LastWindowPosition.swift */; };
A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A5B30538299BEAAB0047F10C /* Assets.xcassets */; };
A5B4EA852DFE691B0022C3A2 /* NSMenuItem+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5B4EA842DFE69140022C3A2 /* NSMenuItem+Extension.swift */; };
A5BB78B92DF9D8CE009AC3FA /* QuickTerminalSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5BB78B82DF9D8CE009AC3FA /* QuickTerminalSize.swift */; };
A5CA378C2D2A4DEB00931030 /* KeyboardLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CA378B2D2A4DE800931030 /* KeyboardLayout.swift */; };
A5CA378E2D31D6C300931030 /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CA378D2D31D6C100931030 /* Weak.swift */; };
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */; };
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0572C9F30860017A1AE /* Cursor.swift */; };
A5CBD0592C9F37B10017A1AE /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CEAFFE29C2410700646FDA /* Backport.swift */; };
A5CBD05C2CA0C5C70017A1AE /* QuickTerminal.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5CBD05B2CA0C5C70017A1AE /* QuickTerminal.xib */; };
A5CBD05E2CA0C5EC0017A1AE /* QuickTerminalController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD05D2CA0C5E70017A1AE /* QuickTerminalController.swift */; };
A5CBD0602CA0C90A0017A1AE /* QuickTerminalWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD05F2CA0C9080017A1AE /* QuickTerminalWindow.swift */; };
A5CBD0642CA122E70017A1AE /* QuickTerminalPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD0632CA122E70017A1AE /* QuickTerminalPosition.swift */; };
A5CBD06B2CA322430017A1AE /* GlobalEventTap.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CBD06A2CA322320017A1AE /* GlobalEventTap.swift */; };
A5CC36132C9CD72D004D6760 /* SecureInputOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CC36122C9CD729004D6760 /* SecureInputOverlay.swift */; };
A5CC36152C9CDA06004D6760 /* View+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CC36142C9CDA03004D6760 /* View+Extension.swift */; };
A5CDF1912AAF9A5800513312 /* ConfigurationErrors.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5CDF1902AAF9A5800513312 /* ConfigurationErrors.xib */; };
A5CDF1932AAF9E0800513312 /* ConfigurationErrorsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CDF1922AAF9E0800513312 /* ConfigurationErrorsController.swift */; };
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CDF1942AAFA19600513312 /* ConfigurationErrorsView.swift */; };
A5CEAFDC29B8009000646FDA /* SplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CEAFDB29B8009000646FDA /* SplitView.swift */; };
A5CEAFDE29B8058B00646FDA /* SplitView.Divider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CEAFDD29B8058B00646FDA /* SplitView.Divider.swift */; };
A5CEAFFF29C2410700646FDA /* Backport.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CEAFFE29C2410700646FDA /* Backport.swift */; };
A5CF66D42D289CEE00139794 /* NSEvent+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CF66D32D289CEA00139794 /* NSEvent+Extension.swift */; };
A5CF66D72D29DDB500139794 /* Ghostty.Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5CF66D62D29DDB100139794 /* Ghostty.Event.swift */; };
A5D0AF3B2B36A1DE00D21823 /* TerminalRestorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D0AF3A2B36A1DE00D21823 /* TerminalRestorable.swift */; };
A5D0AF3D2B37804400D21823 /* CodableBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5D0AF3C2B37804400D21823 /* CodableBridge.swift */; };
A5D689BE2E654D98002E2346 /* Ghostty.Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53A6C022CCC1B7D00943E98 /* Ghostty.Action.swift */; };
A5E112932AF73E6E00C6E0C2 /* ClipboardConfirmation.xib in Resources */ = {isa = PBXBuildFile; fileRef = A5E112922AF73E6E00C6E0C2 /* ClipboardConfirmation.xib */; };
A5E112952AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E112942AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift */; };
A5E112972AF7401B00C6E0C2 /* ClipboardConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E112962AF7401B00C6E0C2 /* ClipboardConfirmationView.swift */; };
A5E4082A2E022E9E0035FEAC /* TabGroupCloseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E408292E022E9B0035FEAC /* TabGroupCloseCoordinator.swift */; };
A5E4082E2E0237460035FEAC /* NewTerminalIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E4082D2E0237410035FEAC /* NewTerminalIntent.swift */; };
A5E408302E0271320035FEAC /* GhosttyIntentError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E4082F2E0271320035FEAC /* GhosttyIntentError.swift */; };
A5E408322E02FEDF0035FEAC /* TerminalEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E408312E02FEDC0035FEAC /* TerminalEntity.swift */; };
A5E408342E0320140035FEAC /* GetTerminalDetailsIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E408332E03200F0035FEAC /* GetTerminalDetailsIntent.swift */; };
A5E408382E03C7DA0035FEAC /* Ghostty.Surface.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E408372E03C7D80035FEAC /* Ghostty.Surface.swift */; };
A5E4083A2E0449BD0035FEAC /* Ghostty.Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E408392E0449BB0035FEAC /* Ghostty.Command.swift */; };
A5E4083C2E044DB50035FEAC /* Ghostty.Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E4083B2E044DB40035FEAC /* Ghostty.Error.swift */; };
A5E408402E04532C0035FEAC /* CommandEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E4083F2E04532A0035FEAC /* CommandEntity.swift */; };
A5E408432E047D0B0035FEAC /* CommandPaletteIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E408422E047D060035FEAC /* CommandPaletteIntent.swift */; };
A5E408452E0483FD0035FEAC /* KeybindIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E408442E0483F80035FEAC /* KeybindIntent.swift */; };
A5E408472E04852B0035FEAC /* InputIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5E408462E0485270035FEAC /* InputIntent.swift */; };
A5F9A1F22E7C7301005AFACE /* SurfaceProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5F9A1F12E7C7301005AFACE /* SurfaceProgressBar.swift */; };
A5FEB3002ABB69450068369E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5FEB2FF2ABB69450068369E /* main.swift */; };
AEE8B3452B9AA39600260C5E /* NSPasteboard+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */; };
C159E81D2B66A06B00FDFE9C /* OSColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */; };
C159E89D2B69A2EF00FDFE9C /* OSColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */; };
C1F26EA72B738B9900404083 /* NSView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1F26EA62B738B9900404083 /* NSView+Extension.swift */; };
C1F26EE92B76CBFC00404083 /* VibrantLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = C1F26EE82B76CBFC00404083 /* VibrantLayer.m */; };
CFBB5FEA2D231E5000FD62EE /* QuickTerminalSpaceBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFBB5FE92D231E5000FD62EE /* QuickTerminalSpaceBehavior.swift */; };
FC5218FA2D10FFCE004C93E0 /* zsh in Resources */ = {isa = PBXBuildFile; fileRef = FC5218F92D10FFC7004C93E0 /* zsh */; };
FC9ABA9C2D0F53F80020D4C8 /* bash-completion in Resources */ = {isa = PBXBuildFile; fileRef = FC9ABA9B2D0F538D0020D4C8 /* bash-completion */; };
/* End PBXBuildFile section */
@@ -170,144 +42,145 @@
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = GhosttyReleaseLocal.entitlements; sourceTree = "<group>"; };
55154BDF2B33911F001622DC /* ghostty */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ghostty; path = "../zig-out/share/ghostty"; sourceTree = "<group>"; };
552964E52B34A9B400030505 /* vim */ = {isa = PBXFileReference; lastKnownFileType = folder; name = vim; path = "../zig-out/share/vim"; sourceTree = "<group>"; };
857F63802A5E64F200CA4815 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; };
9351BE8E2D22937F003B3499 /* nvim */ = {isa = PBXFileReference; lastKnownFileType = folder; name = nvim; path = "../zig-out/share/nvim"; sourceTree = "<group>"; };
A50297342DFA0F3300B4E924 /* Double+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Extension.swift"; sourceTree = "<group>"; };
A505D21C2E1A2F9E0018808F /* FileHandle+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileHandle+Extension.swift"; sourceTree = "<group>"; };
A505D21E2E1B6DDC0018808F /* NSWorkspace+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSWorkspace+Extension.swift"; sourceTree = "<group>"; };
A511940E2E050590007258CC /* CloseTerminalIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseTerminalIntent.swift; sourceTree = "<group>"; };
A51194102E05A480007258CC /* QuickTerminalIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTerminalIntent.swift; sourceTree = "<group>"; };
A51194122E05D003007258CC /* Optional+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Extension.swift"; sourceTree = "<group>"; };
A51194162E05D95E007258CC /* PermissionRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionRequest.swift; sourceTree = "<group>"; };
A51194182E05DFBB007258CC /* IntentPermission.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentPermission.swift; sourceTree = "<group>"; };
A514C8D52B54A16400493A16 /* Ghostty.Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Config.swift; sourceTree = "<group>"; };
A51544FD2DFB1110009E85D8 /* TitlebarTabsTahoeTerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitlebarTabsTahoeTerminalWindow.swift; sourceTree = "<group>"; };
A51544FF2DFB112E009E85D8 /* TerminalTabsTitlebarTahoe.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TerminalTabsTitlebarTahoe.xib; sourceTree = "<group>"; };
A51B78462AF4B58B00F3EDB9 /* TitlebarTabsVenturaTerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitlebarTabsVenturaTerminalWindow.swift; sourceTree = "<group>"; };
A51BFC1D2B2FB5CE00E92F16 /* About.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = About.xib; sourceTree = "<group>"; };
A51BFC1F2B2FB64F00E92F16 /* AboutController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutController.swift; sourceTree = "<group>"; };
A51BFC212B2FB6B400E92F16 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = GhosttyDebug.entitlements; sourceTree = "<group>"; };
A51BFC2A2B30F6BE00E92F16 /* UpdateDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateDelegate.swift; sourceTree = "<group>"; };
A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Input.swift; sourceTree = "<group>"; };
A52FFF562CA90481000C6A5B /* QuickTerminalScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTerminalScreen.swift; sourceTree = "<group>"; };
A52FFF582CAA4FF1000C6A5B /* Fullscreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fullscreen.swift; sourceTree = "<group>"; };
A52FFF5A2CAA54A8000C6A5B /* FullscreenMode+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FullscreenMode+Extension.swift"; sourceTree = "<group>"; };
A52FFF5C2CAB4D05000C6A5B /* NSScreen+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSScreen+Extension.swift"; sourceTree = "<group>"; };
A5333E152B59DE8E008AEFF7 /* SurfaceView_UIKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurfaceView_UIKit.swift; sourceTree = "<group>"; };
A5333E1B2B5A1CE3008AEFF7 /* CrossKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrossKit.swift; sourceTree = "<group>"; };
A5333E212B5A2128008AEFF7 /* SurfaceView_AppKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurfaceView_AppKit.swift; sourceTree = "<group>"; };
A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
A535B9D9299C569B0017E2E4 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; };
A53A297A2DB2E49400B6E02C /* CommandPalette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandPalette.swift; sourceTree = "<group>"; };
A53A297E2DB4480A00B6E02C /* EventModifiers+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "EventModifiers+Extension.swift"; sourceTree = "<group>"; };
A53A29802DB44A5E00B6E02C /* KeyboardShortcut+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyboardShortcut+Extension.swift"; sourceTree = "<group>"; };
A53A29872DB69D2C00B6E02C /* TerminalCommandPalette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalCommandPalette.swift; sourceTree = "<group>"; };
A53A6C022CCC1B7D00943E98 /* Ghostty.Action.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Action.swift; sourceTree = "<group>"; };
A53D0C932B53B43700305CE6 /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; };
A53D0C992B543F3B00305CE6 /* Ghostty.App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.App.swift; sourceTree = "<group>"; };
A546F1132D7B68D7003B11A0 /* locale */ = {isa = PBXFileReference; lastKnownFileType = folder; name = locale; path = "../zig-out/share/locale"; sourceTree = "<group>"; };
A54B0CE82D0CECD100CBEFF8 /* ColorizedGhosttyIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorizedGhosttyIconView.swift; sourceTree = "<group>"; };
A54B0CEA2D0CFB4A00CBEFF8 /* NSImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSImage+Extension.swift"; sourceTree = "<group>"; };
A54B0CEC2D0CFB7300CBEFF8 /* ColorizedGhosttyIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorizedGhosttyIcon.swift; sourceTree = "<group>"; };
A54B0CEE2D0D2E2400CBEFF8 /* ColorizedGhosttyIconImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorizedGhosttyIconImage.swift; sourceTree = "<group>"; };
A54D786B2CA79788001B19B1 /* BaseTerminalController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTerminalController.swift; sourceTree = "<group>"; };
A54F45F32E1F047A0046BD5C /* GhosttyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GhosttyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
A553F4122E06EB1600257779 /* Ghostty.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; name = Ghostty.icon; path = ../images/Ghostty.icon; sourceTree = SOURCE_ROOT; };
A5593FDE2DF8D57100B47B10 /* TerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalWindow.swift; sourceTree = "<group>"; };
A5593FE02DF8D73400B47B10 /* HiddenTitlebarTerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HiddenTitlebarTerminalWindow.swift; sourceTree = "<group>"; };
A5593FE22DF8D78600B47B10 /* TerminalHiddenTitlebar.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TerminalHiddenTitlebar.xib; sourceTree = "<group>"; };
A5593FE42DF8DE3000B47B10 /* TerminalTabsTitlebarVentura.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TerminalTabsTitlebarVentura.xib; sourceTree = "<group>"; };
A5593FE62DF927CC00B47B10 /* TransparentTitlebarTerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransparentTitlebarTerminalWindow.swift; sourceTree = "<group>"; };
A5593FE82DF927DF00B47B10 /* TerminalTransparentTitlebar.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TerminalTransparentTitlebar.xib; sourceTree = "<group>"; };
A55B7BB729B6F53A0055DE60 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
A55B7BBB29B6FC330055DE60 /* SurfaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurfaceView.swift; sourceTree = "<group>"; };
A56B880A2A840447007A0E29 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
A56D58852ACDDB4100508D2C /* Ghostty.Shell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Shell.swift; sourceTree = "<group>"; };
A56D58882ACDE6CA00508D2C /* ServiceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceProvider.swift; sourceTree = "<group>"; };
A571AB1C2A206FC600248498 /* Ghostty-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "Ghostty-Info.plist"; sourceTree = "<group>"; };
A57D79262C9C8798001D522E /* SecureInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureInput.swift; sourceTree = "<group>"; };
A586167B2B7703CC009BDB1D /* fish */ = {isa = PBXFileReference; lastKnownFileType = folder; name = fish; path = "../zig-out/share/fish"; sourceTree = "<group>"; };
A586365E2DEE6C2100E04A10 /* SplitTree.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitTree.swift; sourceTree = "<group>"; };
A58636652DEF963F00E04A10 /* TerminalSplitTreeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalSplitTreeView.swift; sourceTree = "<group>"; };
A586366A2DF0A98900E04A10 /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = "<group>"; };
A586366E2DF25D8300E04A10 /* Duration+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Duration+Extension.swift"; sourceTree = "<group>"; };
A58636702DF298F700E04A10 /* ExpiringUndoManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpiringUndoManager.swift; sourceTree = "<group>"; };
A58636722DF4813000E04A10 /* UndoManager+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UndoManager+Extension.swift"; sourceTree = "<group>"; };
A5874D982DAD751A00E83852 /* CGS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGS.swift; sourceTree = "<group>"; };
A5874D9C2DAD785F00E83852 /* NSWindow+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSWindow+Extension.swift"; sourceTree = "<group>"; };
A59444F629A2ED5200725BBA /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
A59630962AEE163600D64628 /* HostingWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingWindow.swift; sourceTree = "<group>"; };
A59630992AEE1C6400D64628 /* Terminal.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = Terminal.xib; sourceTree = "<group>"; };
A596309B2AEE1C9E00D64628 /* TerminalController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalController.swift; sourceTree = "<group>"; };
A596309D2AEE1D6C00D64628 /* TerminalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalView.swift; sourceTree = "<group>"; };
A5985CD62C320C4500C57AD3 /* String+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = "<group>"; };
A5985CE52C33060F00C57AD3 /* man */ = {isa = PBXFileReference; lastKnownFileType = folder; name = man; path = "../zig-out/share/man"; sourceTree = "<group>"; };
A599CDAF2CF103F20049FA26 /* NSAppearance+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAppearance+Extension.swift"; sourceTree = "<group>"; };
A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorView.swift; sourceTree = "<group>"; };
A59FB5D02AE0DEA7009128F3 /* MetalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetalView.swift; sourceTree = "<group>"; };
A5A1F8842A489D6800D1E8BC /* terminfo */ = {isa = PBXFileReference; lastKnownFileType = folder; name = terminfo; path = "../zig-out/share/terminfo"; sourceTree = "<group>"; };
A5A2A3C92D4445E20033CF96 /* Dock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dock.swift; sourceTree = "<group>"; };
A5A2A3CB2D444AB80033CF96 /* NSApplication+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSApplication+Extension.swift"; sourceTree = "<group>"; };
A5A6F7292CC41B8700B232A5 /* AppInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppInfo.swift; sourceTree = "<group>"; };
A5AEB1642D5BE7BF00513529 /* LastWindowPosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastWindowPosition.swift; sourceTree = "<group>"; };
A5B30531299BEAAA0047F10C /* Ghostty.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ghostty.app; sourceTree = BUILT_PRODUCTS_DIR; };
A5B30538299BEAAB0047F10C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ghostty.entitlements; sourceTree = "<group>"; };
A5B4EA842DFE69140022C3A2 /* NSMenuItem+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMenuItem+Extension.swift"; sourceTree = "<group>"; };
A5BB78B82DF9D8CE009AC3FA /* QuickTerminalSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTerminalSize.swift; sourceTree = "<group>"; };
A5CA378B2D2A4DE800931030 /* KeyboardLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardLayout.swift; sourceTree = "<group>"; };
A5CA378D2D31D6C100931030 /* Weak.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Weak.swift; sourceTree = "<group>"; };
A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggableWindowView.swift; sourceTree = "<group>"; };
A5CBD0572C9F30860017A1AE /* Cursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cursor.swift; sourceTree = "<group>"; };
A5CBD05B2CA0C5C70017A1AE /* QuickTerminal.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = QuickTerminal.xib; sourceTree = "<group>"; };
A5CBD05D2CA0C5E70017A1AE /* QuickTerminalController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTerminalController.swift; sourceTree = "<group>"; };
A5CBD05F2CA0C9080017A1AE /* QuickTerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTerminalWindow.swift; sourceTree = "<group>"; };
A5CBD0632CA122E70017A1AE /* QuickTerminalPosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTerminalPosition.swift; sourceTree = "<group>"; };
A5CBD06A2CA322320017A1AE /* GlobalEventTap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalEventTap.swift; sourceTree = "<group>"; };
A5CC36122C9CD729004D6760 /* SecureInputOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureInputOverlay.swift; sourceTree = "<group>"; };
A5CC36142C9CDA03004D6760 /* View+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extension.swift"; sourceTree = "<group>"; };
A5CDF1902AAF9A5800513312 /* ConfigurationErrors.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ConfigurationErrors.xib; sourceTree = "<group>"; };
A5CDF1922AAF9E0800513312 /* ConfigurationErrorsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationErrorsController.swift; sourceTree = "<group>"; };
A5CDF1942AAFA19600513312 /* ConfigurationErrorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationErrorsView.swift; sourceTree = "<group>"; };
A5CEAFDB29B8009000646FDA /* SplitView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitView.swift; sourceTree = "<group>"; };
A5CEAFDD29B8058B00646FDA /* SplitView.Divider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitView.Divider.swift; sourceTree = "<group>"; };
A5CEAFFE29C2410700646FDA /* Backport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Backport.swift; sourceTree = "<group>"; };
A5CF66D32D289CEA00139794 /* NSEvent+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSEvent+Extension.swift"; sourceTree = "<group>"; };
A5CF66D62D29DDB100139794 /* Ghostty.Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Event.swift; sourceTree = "<group>"; };
A5D0AF3A2B36A1DE00D21823 /* TerminalRestorable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalRestorable.swift; sourceTree = "<group>"; };
A5D0AF3C2B37804400D21823 /* CodableBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodableBridge.swift; sourceTree = "<group>"; };
A5D4499D2B53AE7B000F5B83 /* Ghostty-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Ghostty-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
A5D495A1299BEC7E00DD1313 /* GhosttyKit.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = GhosttyKit.xcframework; sourceTree = "<group>"; };
A5E112922AF73E6E00C6E0C2 /* ClipboardConfirmation.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ClipboardConfirmation.xib; sourceTree = "<group>"; };
A5E112942AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClipboardConfirmationController.swift; sourceTree = "<group>"; };
A5E112962AF7401B00C6E0C2 /* ClipboardConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClipboardConfirmationView.swift; sourceTree = "<group>"; };
A5E408292E022E9B0035FEAC /* TabGroupCloseCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabGroupCloseCoordinator.swift; sourceTree = "<group>"; };
A5E4082D2E0237410035FEAC /* NewTerminalIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTerminalIntent.swift; sourceTree = "<group>"; };
A5E4082F2E0271320035FEAC /* GhosttyIntentError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GhosttyIntentError.swift; sourceTree = "<group>"; };
A5E408312E02FEDC0035FEAC /* TerminalEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalEntity.swift; sourceTree = "<group>"; };
A5E408332E03200F0035FEAC /* GetTerminalDetailsIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetTerminalDetailsIntent.swift; sourceTree = "<group>"; };
A5E408372E03C7D80035FEAC /* Ghostty.Surface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Surface.swift; sourceTree = "<group>"; };
A5E408392E0449BB0035FEAC /* Ghostty.Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Command.swift; sourceTree = "<group>"; };
A5E4083B2E044DB40035FEAC /* Ghostty.Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Error.swift; sourceTree = "<group>"; };
A5E4083F2E04532A0035FEAC /* CommandEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandEntity.swift; sourceTree = "<group>"; };
A5E408422E047D060035FEAC /* CommandPaletteIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandPaletteIntent.swift; sourceTree = "<group>"; };
A5E408442E0483F80035FEAC /* KeybindIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeybindIntent.swift; sourceTree = "<group>"; };
A5E408462E0485270035FEAC /* InputIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputIntent.swift; sourceTree = "<group>"; };
A5F9A1F12E7C7301005AFACE /* SurfaceProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurfaceProgressBar.swift; sourceTree = "<group>"; };
A5FEB2FF2ABB69450068369E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSPasteboard+Extension.swift"; sourceTree = "<group>"; };
C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OSColor+Extension.swift"; sourceTree = "<group>"; };
C1F26EA62B738B9900404083 /* NSView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSView+Extension.swift"; sourceTree = "<group>"; };
C1F26EE72B76CBFC00404083 /* VibrantLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VibrantLayer.h; sourceTree = "<group>"; };
C1F26EE82B76CBFC00404083 /* VibrantLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VibrantLayer.m; sourceTree = "<group>"; };
C1F26EEA2B76CC2400404083 /* ghostty-bridging-header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ghostty-bridging-header.h"; sourceTree = "<group>"; };
CFBB5FE92D231E5000FD62EE /* QuickTerminalSpaceBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickTerminalSpaceBehavior.swift; sourceTree = "<group>"; };
FC5218F92D10FFC7004C93E0 /* zsh */ = {isa = PBXFileReference; lastKnownFileType = folder; name = zsh; path = "../zig-out/share/zsh"; sourceTree = "<group>"; };
FC9ABA9B2D0F538D0020D4C8 /* bash-completion */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "bash-completion"; path = "../zig-out/share/bash-completion"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
81F82CB02E8281F5001EDFA7 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
App/macOS/AppDelegate.swift,
App/macOS/main.swift,
App/macOS/MainMenu.xib,
Features/About/About.xib,
Features/About/AboutController.swift,
Features/About/AboutView.swift,
"Features/App Intents/CloseTerminalIntent.swift",
"Features/App Intents/CommandPaletteIntent.swift",
"Features/App Intents/Entities/CommandEntity.swift",
"Features/App Intents/Entities/TerminalEntity.swift",
"Features/App Intents/FocusTerminalIntent.swift",
"Features/App Intents/GetTerminalDetailsIntent.swift",
"Features/App Intents/GhosttyIntentError.swift",
"Features/App Intents/InputIntent.swift",
"Features/App Intents/IntentPermission.swift",
"Features/App Intents/KeybindIntent.swift",
"Features/App Intents/NewTerminalIntent.swift",
"Features/App Intents/QuickTerminalIntent.swift",
Features/ClipboardConfirmation/ClipboardConfirmation.xib,
Features/ClipboardConfirmation/ClipboardConfirmationController.swift,
Features/ClipboardConfirmation/ClipboardConfirmationView.swift,
"Features/Colorized Ghostty Icon/ColorizedGhosttyIcon.swift",
"Features/Colorized Ghostty Icon/ColorizedGhosttyIconImage.swift",
"Features/Colorized Ghostty Icon/ColorizedGhosttyIconView.swift",
"Features/Command Palette/CommandPalette.swift",
"Features/Command Palette/TerminalCommandPalette.swift",
"Features/Global Keybinds/GlobalEventTap.swift",
Features/QuickTerminal/QuickTerminal.xib,
Features/QuickTerminal/QuickTerminalController.swift,
Features/QuickTerminal/QuickTerminalPosition.swift,
Features/QuickTerminal/QuickTerminalScreen.swift,
Features/QuickTerminal/QuickTerminalSize.swift,
Features/QuickTerminal/QuickTerminalSpaceBehavior.swift,
Features/QuickTerminal/QuickTerminalWindow.swift,
"Features/Secure Input/SecureInput.swift",
"Features/Secure Input/SecureInputOverlay.swift",
Features/Services/ServiceProvider.swift,
Features/Settings/ConfigurationErrors.xib,
Features/Settings/ConfigurationErrorsController.swift,
Features/Settings/ConfigurationErrorsView.swift,
Features/Settings/SettingsView.swift,
Features/Splits/SplitTree.swift,
Features/Splits/SplitView.Divider.swift,
Features/Splits/SplitView.swift,
Features/Splits/TerminalSplitTreeView.swift,
Features/Terminal/BaseTerminalController.swift,
Features/Terminal/ErrorView.swift,
Features/Terminal/TerminalController.swift,
Features/Terminal/TerminalRestorable.swift,
Features/Terminal/TerminalView.swift,
"Features/Terminal/Window Styles/HiddenTitlebarTerminalWindow.swift",
"Features/Terminal/Window Styles/Terminal.xib",
"Features/Terminal/Window Styles/TerminalHiddenTitlebar.xib",
"Features/Terminal/Window Styles/TerminalTabsTitlebarTahoe.xib",
"Features/Terminal/Window Styles/TerminalTabsTitlebarVentura.xib",
"Features/Terminal/Window Styles/TerminalTransparentTitlebar.xib",
"Features/Terminal/Window Styles/TerminalWindow.swift",
"Features/Terminal/Window Styles/TitlebarTabsTahoeTerminalWindow.swift",
"Features/Terminal/Window Styles/TitlebarTabsVenturaTerminalWindow.swift",
"Features/Terminal/Window Styles/TransparentTitlebarTerminalWindow.swift",
Features/Update/UpdateDelegate.swift,
"Ghostty/FullscreenMode+Extension.swift",
Ghostty/Ghostty.Command.swift,
Ghostty/Ghostty.Error.swift,
Ghostty/Ghostty.Event.swift,
Ghostty/Ghostty.Input.swift,
Ghostty/Ghostty.Surface.swift,
Ghostty/InspectorView.swift,
"Ghostty/NSEvent+Extension.swift",
Ghostty/SurfaceView_AppKit.swift,
Helpers/AppInfo.swift,
Helpers/CodableBridge.swift,
Helpers/Cursor.swift,
Helpers/DraggableWindowView.swift,
Helpers/ExpiringUndoManager.swift,
"Helpers/Extensions/Double+Extension.swift",
"Helpers/Extensions/EventModifiers+Extension.swift",
"Helpers/Extensions/FileHandle+Extension.swift",
"Helpers/Extensions/KeyboardShortcut+Extension.swift",
"Helpers/Extensions/NSAppearance+Extension.swift",
"Helpers/Extensions/NSApplication+Extension.swift",
"Helpers/Extensions/NSImage+Extension.swift",
"Helpers/Extensions/NSMenuItem+Extension.swift",
"Helpers/Extensions/NSPasteboard+Extension.swift",
"Helpers/Extensions/NSScreen+Extension.swift",
"Helpers/Extensions/NSView+Extension.swift",
"Helpers/Extensions/NSWindow+Extension.swift",
"Helpers/Extensions/NSWorkspace+Extension.swift",
"Helpers/Extensions/UndoManager+Extension.swift",
"Helpers/Extensions/View+Extension.swift",
Helpers/Fullscreen.swift,
Helpers/HostingWindow.swift,
Helpers/KeyboardLayout.swift,
Helpers/LastWindowPosition.swift,
Helpers/MetalView.swift,
Helpers/PermissionRequest.swift,
Helpers/Private/CGS.swift,
Helpers/Private/Dock.swift,
Helpers/TabGroupCloseCoordinator.swift,
Helpers/VibrantLayer.m,
Helpers/Weak.swift,
);
target = A5D4499C2B53AE7B000F5B83 /* Ghostty-iOS */;
};
81F82CB12E8281F9001EDFA7 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
App/iOS/iOSApp.swift,
Ghostty/SurfaceView_UIKit.swift,
);
target = A5B30530299BEAAA0047F10C /* Ghostty */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
81F82BC72E82815D001EDFA7 /* Sources */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (81F82CB12E8281F9001EDFA7 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, 81F82CB02E8281F5001EDFA7 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Sources; sourceTree = "<group>"; };
A54F45F42E1F047A0046BD5C /* Tests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Tests; sourceTree = "<group>"; };
/* End PBXFileSystemSynchronizedRootGroup section */
@@ -340,257 +213,6 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
A51BFC1C2B2FB5AB00E92F16 /* About */ = {
isa = PBXGroup;
children = (
A51BFC1D2B2FB5CE00E92F16 /* About.xib */,
A51BFC1F2B2FB64F00E92F16 /* AboutController.swift */,
A51BFC212B2FB6B400E92F16 /* AboutView.swift */,
);
path = About;
sourceTree = "<group>";
};
A51BFC292B30F69F00E92F16 /* Update */ = {
isa = PBXGroup;
children = (
A51BFC2A2B30F6BE00E92F16 /* UpdateDelegate.swift */,
);
path = Update;
sourceTree = "<group>";
};
A53426362A7DC53000EBB7A2 /* Features */ = {
isa = PBXGroup;
children = (
A5CBD0672CA2704E0017A1AE /* Global Keybinds */,
A56D58872ACDE6BE00508D2C /* Services */,
A59630982AEE1C4400D64628 /* Terminal */,
A5CBD05A2CA0C5910017A1AE /* QuickTerminal */,
A5E4082C2E0237270035FEAC /* App Intents */,
A5E112912AF73E4D00C6E0C2 /* ClipboardConfirmation */,
A57D79252C9C8782001D522E /* Secure Input */,
A58636622DEF955100E04A10 /* Splits */,
A53A29742DB2E04900B6E02C /* Command Palette */,
A534263E2A7DCC5800EBB7A2 /* Settings */,
A51BFC1C2B2FB5AB00E92F16 /* About */,
A54B0CE72D0CEC9800CBEFF8 /* Colorized Ghostty Icon */,
A51BFC292B30F69F00E92F16 /* Update */,
);
path = Features;
sourceTree = "<group>";
};
A534263D2A7DCBB000EBB7A2 /* Helpers */ = {
isa = PBXGroup;
children = (
A58636692DF0A98100E04A10 /* Extensions */,
A5874D9B2DAD781100E83852 /* Private */,
A5A6F7292CC41B8700B232A5 /* AppInfo.swift */,
A5AEB1642D5BE7BF00513529 /* LastWindowPosition.swift */,
A5CEAFFE29C2410700646FDA /* Backport.swift */,
A5333E1B2B5A1CE3008AEFF7 /* CrossKit.swift */,
A5CBD0572C9F30860017A1AE /* Cursor.swift */,
A5D0AF3C2B37804400D21823 /* CodableBridge.swift */,
A5CBD0552C9E65A50017A1AE /* DraggableWindowView.swift */,
A58636702DF298F700E04A10 /* ExpiringUndoManager.swift */,
A52FFF582CAA4FF1000C6A5B /* Fullscreen.swift */,
A59630962AEE163600D64628 /* HostingWindow.swift */,
A5CA378B2D2A4DE800931030 /* KeyboardLayout.swift */,
A59FB5D02AE0DEA7009128F3 /* MetalView.swift */,
A51194162E05D95E007258CC /* PermissionRequest.swift */,
A5E408292E022E9B0035FEAC /* TabGroupCloseCoordinator.swift */,
A5CA378D2D31D6C100931030 /* Weak.swift */,
C1F26EE72B76CBFC00404083 /* VibrantLayer.h */,
C1F26EE82B76CBFC00404083 /* VibrantLayer.m */,
);
path = Helpers;
sourceTree = "<group>";
};
A534263E2A7DCC5800EBB7A2 /* Settings */ = {
isa = PBXGroup;
children = (
A59444F629A2ED5200725BBA /* SettingsView.swift */,
A5CDF1902AAF9A5800513312 /* ConfigurationErrors.xib */,
A5CDF1922AAF9E0800513312 /* ConfigurationErrorsController.swift */,
A5CDF1942AAFA19600513312 /* ConfigurationErrorsView.swift */,
);
path = Settings;
sourceTree = "<group>";
};
A53A29742DB2E04900B6E02C /* Command Palette */ = {
isa = PBXGroup;
children = (
A53A297A2DB2E49400B6E02C /* CommandPalette.swift */,
A53A29872DB69D2C00B6E02C /* TerminalCommandPalette.swift */,
);
path = "Command Palette";
sourceTree = "<group>";
};
A53D0C912B53B41900305CE6 /* App */ = {
isa = PBXGroup;
children = (
A53D0C962B53B57D00305CE6 /* macOS */,
A53D0C922B53B42000305CE6 /* iOS */,
);
path = App;
sourceTree = "<group>";
};
A53D0C922B53B42000305CE6 /* iOS */ = {
isa = PBXGroup;
children = (
A53D0C932B53B43700305CE6 /* iOSApp.swift */,
);
path = iOS;
sourceTree = "<group>";
};
A53D0C962B53B57D00305CE6 /* macOS */ = {
isa = PBXGroup;
children = (
A5FEB2FF2ABB69450068369E /* main.swift */,
A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */,
857F63802A5E64F200CA4815 /* MainMenu.xib */,
C1F26EEA2B76CC2400404083 /* ghostty-bridging-header.h */,
);
path = macOS;
sourceTree = "<group>";
};
A54B0CE72D0CEC9800CBEFF8 /* Colorized Ghostty Icon */ = {
isa = PBXGroup;
children = (
A54B0CEC2D0CFB7300CBEFF8 /* ColorizedGhosttyIcon.swift */,
A54B0CEE2D0D2E2400CBEFF8 /* ColorizedGhosttyIconImage.swift */,
A54B0CE82D0CECD100CBEFF8 /* ColorizedGhosttyIconView.swift */,
);
path = "Colorized Ghostty Icon";
sourceTree = "<group>";
};
A54CD6ED299BEB14008C95BB /* Sources */ = {
isa = PBXGroup;
children = (
A53D0C912B53B41900305CE6 /* App */,
A53426362A7DC53000EBB7A2 /* Features */,
A534263D2A7DCBB000EBB7A2 /* Helpers */,
A55B7BB429B6F4410055DE60 /* Ghostty */,
);
path = Sources;
sourceTree = "<group>";
};
A5593FDD2DF8D56000B47B10 /* Window Styles */ = {
isa = PBXGroup;
children = (
A59630992AEE1C6400D64628 /* Terminal.xib */,
A5593FE22DF8D78600B47B10 /* TerminalHiddenTitlebar.xib */,
A51544FF2DFB112E009E85D8 /* TerminalTabsTitlebarTahoe.xib */,
A5593FE42DF8DE3000B47B10 /* TerminalTabsTitlebarVentura.xib */,
A5593FE82DF927DF00B47B10 /* TerminalTransparentTitlebar.xib */,
A5593FDE2DF8D57100B47B10 /* TerminalWindow.swift */,
A5593FE02DF8D73400B47B10 /* HiddenTitlebarTerminalWindow.swift */,
A51B78462AF4B58B00F3EDB9 /* TitlebarTabsVenturaTerminalWindow.swift */,
A51544FD2DFB1110009E85D8 /* TitlebarTabsTahoeTerminalWindow.swift */,
A5593FE62DF927CC00B47B10 /* TransparentTitlebarTerminalWindow.swift */,
);
path = "Window Styles";
sourceTree = "<group>";
};
A55B7BB429B6F4410055DE60 /* Ghostty */ = {
isa = PBXGroup;
children = (
A55B7BB729B6F53A0055DE60 /* Package.swift */,
A5F9A1F12E7C7301005AFACE /* SurfaceProgressBar.swift */,
A55B7BBB29B6FC330055DE60 /* SurfaceView.swift */,
A5333E212B5A2128008AEFF7 /* SurfaceView_AppKit.swift */,
A5333E152B59DE8E008AEFF7 /* SurfaceView_UIKit.swift */,
A59FB5CE2AE0DB50009128F3 /* InspectorView.swift */,
A53D0C992B543F3B00305CE6 /* Ghostty.App.swift */,
A5E408392E0449BB0035FEAC /* Ghostty.Command.swift */,
A514C8D52B54A16400493A16 /* Ghostty.Config.swift */,
A53A6C022CCC1B7D00943E98 /* Ghostty.Action.swift */,
A5E4083B2E044DB40035FEAC /* Ghostty.Error.swift */,
A5CF66D62D29DDB100139794 /* Ghostty.Event.swift */,
A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */,
A56D58852ACDDB4100508D2C /* Ghostty.Shell.swift */,
A5E408372E03C7D80035FEAC /* Ghostty.Surface.swift */,
A52FFF5A2CAA54A8000C6A5B /* FullscreenMode+Extension.swift */,
A5CF66D32D289CEA00139794 /* NSEvent+Extension.swift */,
);
path = Ghostty;
sourceTree = "<group>";
};
A56D58872ACDE6BE00508D2C /* Services */ = {
isa = PBXGroup;
children = (
A56D58882ACDE6CA00508D2C /* ServiceProvider.swift */,
);
path = Services;
sourceTree = "<group>";
};
A57D79252C9C8782001D522E /* Secure Input */ = {
isa = PBXGroup;
children = (
A57D79262C9C8798001D522E /* SecureInput.swift */,
A5CC36122C9CD729004D6760 /* SecureInputOverlay.swift */,
);
path = "Secure Input";
sourceTree = "<group>";
};
A58636622DEF955100E04A10 /* Splits */ = {
isa = PBXGroup;
children = (
A586365E2DEE6C2100E04A10 /* SplitTree.swift */,
A58636652DEF963F00E04A10 /* TerminalSplitTreeView.swift */,
A5CEAFDB29B8009000646FDA /* SplitView.swift */,
A5CEAFDD29B8058B00646FDA /* SplitView.Divider.swift */,
);
path = Splits;
sourceTree = "<group>";
};
A58636692DF0A98100E04A10 /* Extensions */ = {
isa = PBXGroup;
children = (
A586366A2DF0A98900E04A10 /* Array+Extension.swift */,
A50297342DFA0F3300B4E924 /* Double+Extension.swift */,
A586366E2DF25D8300E04A10 /* Duration+Extension.swift */,
A505D21C2E1A2F9E0018808F /* FileHandle+Extension.swift */,
A53A29802DB44A5E00B6E02C /* KeyboardShortcut+Extension.swift */,
A53A297E2DB4480A00B6E02C /* EventModifiers+Extension.swift */,
A51194122E05D003007258CC /* Optional+Extension.swift */,
C159E81C2B66A06B00FDFE9C /* OSColor+Extension.swift */,
A599CDAF2CF103F20049FA26 /* NSAppearance+Extension.swift */,
A5A2A3CB2D444AB80033CF96 /* NSApplication+Extension.swift */,
A54B0CEA2D0CFB4A00CBEFF8 /* NSImage+Extension.swift */,
A5B4EA842DFE69140022C3A2 /* NSMenuItem+Extension.swift */,
A52FFF5C2CAB4D05000C6A5B /* NSScreen+Extension.swift */,
AEE8B3442B9AA39600260C5E /* NSPasteboard+Extension.swift */,
C1F26EA62B738B9900404083 /* NSView+Extension.swift */,
A5874D9C2DAD785F00E83852 /* NSWindow+Extension.swift */,
A505D21E2E1B6DDC0018808F /* NSWorkspace+Extension.swift */,
A5985CD62C320C4500C57AD3 /* String+Extension.swift */,
A58636722DF4813000E04A10 /* UndoManager+Extension.swift */,
A5CC36142C9CDA03004D6760 /* View+Extension.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
A5874D9B2DAD781100E83852 /* Private */ = {
isa = PBXGroup;
children = (
A5874D982DAD751A00E83852 /* CGS.swift */,
A5A2A3C92D4445E20033CF96 /* Dock.swift */,
);
path = Private;
sourceTree = "<group>";
};
A59630982AEE1C4400D64628 /* Terminal */ = {
isa = PBXGroup;
children = (
A5593FDD2DF8D56000B47B10 /* Window Styles */,
A596309B2AEE1C9E00D64628 /* TerminalController.swift */,
A5D0AF3A2B36A1DE00D21823 /* TerminalRestorable.swift */,
A596309D2AEE1D6C00D64628 /* TerminalView.swift */,
A535B9D9299C569B0017E2E4 /* ErrorView.swift */,
A54D786B2CA79788001B19B1 /* BaseTerminalController.swift */,
);
path = Terminal;
sourceTree = "<group>";
};
A5A1F8862A489D7400D1E8BC /* Resources */ = {
isa = PBXGroup;
children = (
@@ -617,7 +239,7 @@
A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */,
A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */,
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */,
A54CD6ED299BEB14008C95BB /* Sources */,
81F82BC72E82815D001EDFA7 /* Sources */,
A54F45F42E1F047A0046BD5C /* Tests */,
A5D495A3299BECBA00DD1313 /* Frameworks */,
A5A1F8862A489D7400D1E8BC /* Resources */,
@@ -635,28 +257,6 @@
name = Products;
sourceTree = "<group>";
};
A5CBD05A2CA0C5910017A1AE /* QuickTerminal */ = {
isa = PBXGroup;
children = (
A5CBD05B2CA0C5C70017A1AE /* QuickTerminal.xib */,
A5CBD05D2CA0C5E70017A1AE /* QuickTerminalController.swift */,
CFBB5FE92D231E5000FD62EE /* QuickTerminalSpaceBehavior.swift */,
A5CBD0632CA122E70017A1AE /* QuickTerminalPosition.swift */,
A52FFF562CA90481000C6A5B /* QuickTerminalScreen.swift */,
A5BB78B82DF9D8CE009AC3FA /* QuickTerminalSize.swift */,
A5CBD05F2CA0C9080017A1AE /* QuickTerminalWindow.swift */,
);
path = QuickTerminal;
sourceTree = "<group>";
};
A5CBD0672CA2704E0017A1AE /* Global Keybinds */ = {
isa = PBXGroup;
children = (
A5CBD06A2CA322320017A1AE /* GlobalEventTap.swift */,
);
path = "Global Keybinds";
sourceTree = "<group>";
};
A5D495A3299BECBA00DD1313 /* Frameworks */ = {
isa = PBXGroup;
children = (
@@ -666,42 +266,6 @@
name = Frameworks;
sourceTree = "<group>";
};
A5E112912AF73E4D00C6E0C2 /* ClipboardConfirmation */ = {
isa = PBXGroup;
children = (
A5E112922AF73E6E00C6E0C2 /* ClipboardConfirmation.xib */,
A5E112942AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift */,
A5E112962AF7401B00C6E0C2 /* ClipboardConfirmationView.swift */,
);
path = ClipboardConfirmation;
sourceTree = "<group>";
};
A5E4082C2E0237270035FEAC /* App Intents */ = {
isa = PBXGroup;
children = (
A5E408412E0453370035FEAC /* Entities */,
A511940E2E050590007258CC /* CloseTerminalIntent.swift */,
A5E4082D2E0237410035FEAC /* NewTerminalIntent.swift */,
A5E408332E03200F0035FEAC /* GetTerminalDetailsIntent.swift */,
A51194102E05A480007258CC /* QuickTerminalIntent.swift */,
A5E408422E047D060035FEAC /* CommandPaletteIntent.swift */,
A5E408462E0485270035FEAC /* InputIntent.swift */,
A5E408442E0483F80035FEAC /* KeybindIntent.swift */,
A5E4082F2E0271320035FEAC /* GhosttyIntentError.swift */,
A51194182E05DFBB007258CC /* IntentPermission.swift */,
);
path = "App Intents";
sourceTree = "<group>";
};
A5E408412E0453370035FEAC /* Entities */ = {
isa = PBXGroup;
children = (
A5E408312E02FEDC0035FEAC /* TerminalEntity.swift */,
A5E4083F2E04532A0035FEAC /* CommandEntity.swift */,
);
path = Entities;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -740,6 +304,9 @@
);
dependencies = (
);
fileSystemSynchronizedGroups = (
81F82BC72E82815D001EDFA7 /* Sources */,
);
name = Ghostty;
packageProductDependencies = (
A51BFC262B30F1B800E92F16 /* Sparkle */,
@@ -760,6 +327,9 @@
);
dependencies = (
);
fileSystemSynchronizedGroups = (
81F82BC72E82815D001EDFA7 /* Sources */,
);
name = "Ghostty-iOS";
productName = "Ghostty-iOS";
productReference = A5D4499D2B53AE7B000F5B83 /* Ghostty-iOS.app */;
@@ -825,11 +395,9 @@
files = (
FC9ABA9C2D0F53F80020D4C8 /* bash-completion in Resources */,
A553F4142E06EB1600257779 /* Ghostty.icon in Resources */,
A5593FE52DF8DE3000B47B10 /* TerminalTabsTitlebarVentura.xib in Resources */,
29C15B1D2CDC3B2900520DD4 /* bat in Resources */,
A586167C2B7703CC009BDB1D /* fish in Resources */,
55154BE02B33911F001622DC /* ghostty in Resources */,
A5593FE32DF8D78600B47B10 /* TerminalHiddenTitlebar.xib in Resources */,
A546F1142D7B68D7003B11A0 /* locale in Resources */,
A5985CE62C33060F00C57AD3 /* man in Resources */,
9351BE8E3D22937F003B3499 /* nvim in Resources */,
@@ -837,14 +405,6 @@
552964E62B34A9B400030505 /* vim in Resources */,
FC5218FA2D10FFCE004C93E0 /* zsh in Resources */,
A5B30539299BEAAB0047F10C /* Assets.xcassets in Resources */,
A51BFC1E2B2FB5CE00E92F16 /* About.xib in Resources */,
A5593FE92DF927DF00B47B10 /* TerminalTransparentTitlebar.xib in Resources */,
A5E112932AF73E6E00C6E0C2 /* ClipboardConfirmation.xib in Resources */,
A5CDF1912AAF9A5800513312 /* ConfigurationErrors.xib in Resources */,
857F63812A5E64F200CA4815 /* MainMenu.xib in Resources */,
A596309A2AEE1C6400D64628 /* Terminal.xib in Resources */,
A51545002DFB112E009E85D8 /* TerminalTabsTitlebarTahoe.xib in Resources */,
A5CBD05C2CA0C5C70017A1AE /* QuickTerminal.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -871,113 +431,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A5AEB1652D5BE7D000513529 /* LastWindowPosition.swift in Sources */,
A5E408432E047D0B0035FEAC /* CommandPaletteIntent.swift in Sources */,
A514C8D62B54A16400493A16 /* Ghostty.Config.swift in Sources */,
A54B0CEB2D0CFB4C00CBEFF8 /* NSImage+Extension.swift in Sources */,
A5874D9D2DAD786100E83852 /* NSWindow+Extension.swift in Sources */,
A54D786C2CA7978E001B19B1 /* BaseTerminalController.swift in Sources */,
A58636732DF4813400E04A10 /* UndoManager+Extension.swift in Sources */,
A505D21D2E1A2FA20018808F /* FileHandle+Extension.swift in Sources */,
A59FB5CF2AE0DB50009128F3 /* InspectorView.swift in Sources */,
CFBB5FEA2D231E5000FD62EE /* QuickTerminalSpaceBehavior.swift in Sources */,
A54B0CE92D0CECD100CBEFF8 /* ColorizedGhosttyIconView.swift in Sources */,
A5D0AF3D2B37804400D21823 /* CodableBridge.swift in Sources */,
A51194132E05D006007258CC /* Optional+Extension.swift in Sources */,
A5D0AF3B2B36A1DE00D21823 /* TerminalRestorable.swift in Sources */,
C1F26EA72B738B9900404083 /* NSView+Extension.swift in Sources */,
A586366F2DF25D8600E04A10 /* Duration+Extension.swift in Sources */,
A5CF66D42D289CEE00139794 /* NSEvent+Extension.swift in Sources */,
A5E408342E0320140035FEAC /* GetTerminalDetailsIntent.swift in Sources */,
A5CBD0642CA122E70017A1AE /* QuickTerminalPosition.swift in Sources */,
A596309C2AEE1C9E00D64628 /* TerminalController.swift in Sources */,
A5E408322E02FEDF0035FEAC /* TerminalEntity.swift in Sources */,
A5CC36152C9CDA06004D6760 /* View+Extension.swift in Sources */,
A56D58892ACDE6CA00508D2C /* ServiceProvider.swift in Sources */,
A5CBD0602CA0C90A0017A1AE /* QuickTerminalWindow.swift in Sources */,
A5F9A1F22E7C7301005AFACE /* SurfaceProgressBar.swift in Sources */,
A505D21F2E1B6DE00018808F /* NSWorkspace+Extension.swift in Sources */,
A5CBD05E2CA0C5EC0017A1AE /* QuickTerminalController.swift in Sources */,
A5CF66D72D29DDB500139794 /* Ghostty.Event.swift in Sources */,
A511940F2E050595007258CC /* CloseTerminalIntent.swift in Sources */,
A5E408382E03C7DA0035FEAC /* Ghostty.Surface.swift in Sources */,
A5593FE72DF927D200B47B10 /* TransparentTitlebarTerminalWindow.swift in Sources */,
A5A2A3CA2D4445E30033CF96 /* Dock.swift in Sources */,
A586365F2DEE6C2300E04A10 /* SplitTree.swift in Sources */,
A51BFC222B2FB6B400E92F16 /* AboutView.swift in Sources */,
A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */,
A53A29812DB44A6100B6E02C /* KeyboardShortcut+Extension.swift in Sources */,
A50297352DFA0F3400B4E924 /* Double+Extension.swift in Sources */,
A5CBD0562C9E65B80017A1AE /* DraggableWindowView.swift in Sources */,
A51194112E05A483007258CC /* QuickTerminalIntent.swift in Sources */,
C1F26EE92B76CBFC00404083 /* VibrantLayer.m in Sources */,
A5593FDF2DF8D57C00B47B10 /* TerminalWindow.swift in Sources */,
A58636712DF298FB00E04A10 /* ExpiringUndoManager.swift in Sources */,
A59630972AEE163600D64628 /* HostingWindow.swift in Sources */,
A51BFC2B2B30F6BE00E92F16 /* UpdateDelegate.swift in Sources */,
A5CBD06B2CA322430017A1AE /* GlobalEventTap.swift in Sources */,
AEE8B3452B9AA39600260C5E /* NSPasteboard+Extension.swift in Sources */,
A51194172E05D964007258CC /* PermissionRequest.swift in Sources */,
A51194192E05DFC4007258CC /* IntentPermission.swift in Sources */,
A52FFF5D2CAB4D08000C6A5B /* NSScreen+Extension.swift in Sources */,
A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */,
A5CBD0582C9F30960017A1AE /* Cursor.swift in Sources */,
A5A6F72A2CC41B8900B232A5 /* AppInfo.swift in Sources */,
A52FFF5B2CAA54B1000C6A5B /* FullscreenMode+Extension.swift in Sources */,
A5333E222B5A2128008AEFF7 /* SurfaceView_AppKit.swift in Sources */,
A5CA378E2D31D6C300931030 /* Weak.swift in Sources */,
A5CDF1952AAFA19600513312 /* ConfigurationErrorsView.swift in Sources */,
A55B7BBC29B6FC330055DE60 /* SurfaceView.swift in Sources */,
A5333E1C2B5A1CE3008AEFF7 /* CrossKit.swift in Sources */,
A5B4EA852DFE691B0022C3A2 /* NSMenuItem+Extension.swift in Sources */,
A5874D992DAD751B00E83852 /* CGS.swift in Sources */,
A586366B2DF0A98C00E04A10 /* Array+Extension.swift in Sources */,
A5E408472E04852B0035FEAC /* InputIntent.swift in Sources */,
A51544FE2DFB111C009E85D8 /* TitlebarTabsTahoeTerminalWindow.swift in Sources */,
A59444F729A2ED5200725BBA /* SettingsView.swift in Sources */,
A56D58862ACDDB4100508D2C /* Ghostty.Shell.swift in Sources */,
A5985CD72C320C4500C57AD3 /* String+Extension.swift in Sources */,
A5A2A3CC2D444ABB0033CF96 /* NSApplication+Extension.swift in Sources */,
A5E408302E0271320035FEAC /* GhosttyIntentError.swift in Sources */,
A5E4083A2E0449BD0035FEAC /* Ghostty.Command.swift in Sources */,
A5E408452E0483FD0035FEAC /* KeybindIntent.swift in Sources */,
A5FEB3002ABB69450068369E /* main.swift in Sources */,
A53A297F2DB4480F00B6E02C /* EventModifiers+Extension.swift in Sources */,
A5E4082E2E0237460035FEAC /* NewTerminalIntent.swift in Sources */,
A53A297B2DB2E49700B6E02C /* CommandPalette.swift in Sources */,
A55B7BB829B6F53A0055DE60 /* Package.swift in Sources */,
A51B78472AF4B58B00F3EDB9 /* TitlebarTabsVenturaTerminalWindow.swift in Sources */,
A51B78472AF4B58B00F3EDB9 /* TitlebarTabsVenturaTerminalWindow.swift in Sources */,
A5BB78B92DF9D8CE009AC3FA /* QuickTerminalSize.swift in Sources */,
A51B78472AF4B58B00F3EDB9 /* TitlebarTabsVenturaTerminalWindow.swift in Sources */,
A5BB78B92DF9D8CE009AC3FA /* QuickTerminalSize.swift in Sources */,
A57D79272C9C879B001D522E /* SecureInput.swift in Sources */,
A5CEAFDC29B8009000646FDA /* SplitView.swift in Sources */,
A5593FE12DF8D74000B47B10 /* HiddenTitlebarTerminalWindow.swift in Sources */,
A5E4083C2E044DB50035FEAC /* Ghostty.Error.swift in Sources */,
A5CDF1932AAF9E0800513312 /* ConfigurationErrorsController.swift in Sources */,
A53A6C032CCC1B7F00943E98 /* Ghostty.Action.swift in Sources */,
A54B0CED2D0CFB7700CBEFF8 /* ColorizedGhosttyIcon.swift in Sources */,
A5CA378C2D2A4DEB00931030 /* KeyboardLayout.swift in Sources */,
A54B0CEF2D0D2E2800CBEFF8 /* ColorizedGhosttyIconImage.swift in Sources */,
A59FB5D12AE0DEA7009128F3 /* MetalView.swift in Sources */,
A599CDB02CF103F60049FA26 /* NSAppearance+Extension.swift in Sources */,
A52FFF572CA90484000C6A5B /* QuickTerminalScreen.swift in Sources */,
A5CC36132C9CD72D004D6760 /* SecureInputOverlay.swift in Sources */,
A5E408402E04532C0035FEAC /* CommandEntity.swift in Sources */,
A5E4082A2E022E9E0035FEAC /* TabGroupCloseCoordinator.swift in Sources */,
A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */,
A53A29882DB69D2F00B6E02C /* TerminalCommandPalette.swift in Sources */,
A51BFC202B2FB64F00E92F16 /* AboutController.swift in Sources */,
A5CEAFFF29C2410700646FDA /* Backport.swift in Sources */,
A5E112952AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift in Sources */,
A596309E2AEE1D6C00D64628 /* TerminalView.swift in Sources */,
A58636662DEF964100E04A10 /* TerminalSplitTreeView.swift in Sources */,
A52FFF592CAA4FF3000C6A5B /* Fullscreen.swift in Sources */,
C159E81D2B66A06B00FDFE9C /* OSColor+Extension.swift in Sources */,
A5CEAFDE29B8058B00646FDA /* SplitView.Divider.swift in Sources */,
A5E112972AF7401B00C6E0C2 /* ClipboardConfirmationView.swift in Sources */,
A514C8D82B54DC6800493A16 /* Ghostty.App.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -985,20 +438,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A5CBD0592C9F37B10017A1AE /* Backport.swift in Sources */,
A553F4062E05E93000257779 /* Optional+Extension.swift in Sources */,
A53D0C942B53B43700305CE6 /* iOSApp.swift in Sources */,
A514C8D72B54A16400493A16 /* Ghostty.Config.swift in Sources */,
A5333E232B5A219A008AEFF7 /* SurfaceView.swift in Sources */,
A5333E202B5A2111008AEFF7 /* SurfaceView_UIKit.swift in Sources */,
A5333E1D2B5A1CE3008AEFF7 /* CrossKit.swift in Sources */,
A5D689BE2E654D98002E2346 /* Ghostty.Action.swift in Sources */,
A53D0C9C2B543F7B00305CE6 /* Package.swift in Sources */,
A53D0C9B2B543F3B00305CE6 /* Ghostty.App.swift in Sources */,
A5333E242B5A22D9008AEFF7 /* Ghostty.Shell.swift in Sources */,
A5985CD82C320C4500C57AD3 /* String+Extension.swift in Sources */,
A553F4072E05E93D00257779 /* Array+Extension.swift in Sources */,
C159E89D2B69A2EF00FDFE9C /* OSColor+Extension.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -0,0 +1,35 @@
import AppKit
import AppIntents
import GhosttyKit
struct FocusTerminalIntent: AppIntent {
static var title: LocalizedStringResource = "Focus Terminal"
static var description = IntentDescription("Move focus to an existing terminal.")
@Parameter(
title: "Terminal",
description: "The terminal to focus.",
)
var terminal: TerminalEntity
@available(macOS 26.0, *)
static var supportedModes: IntentModes = .background
@MainActor
func perform() async throws -> some IntentResult {
guard await requestIntentPermission() else {
throw GhosttyIntentError.permissionDenied
}
guard let surfaceView = terminal.surfaceView else {
throw GhosttyIntentError.surfaceNotFound
}
guard let controller = surfaceView.window?.windowController as? BaseTerminalController else {
return .result()
}
controller.focusSurface(surfaceView)
return .result()
}
}

View File

@@ -247,6 +247,22 @@ class QuickTerminalController: BaseTerminalController {
// MARK: Base Controller Overrides
override func focusSurface(_ view: Ghostty.SurfaceView) {
if visible {
// If we're visible, we just focus the surface as normal.
super.focusSurface(view)
return
}
// Check if target surface belongs to this quick terminal
guard surfaceTree.contains(view) else { return }
// Set the target surface as focused
DispatchQueue.main.async {
Ghostty.moveFocus(to: view)
}
// Animation completion handler will handle window/app activation
animateIn()
}
override func surfaceTreeDidChange(from: SplitTree<Ghostty.SurfaceView>, to: SplitTree<Ghostty.SurfaceView>) {
super.surfaceTreeDidChange(from: from, to: to)

View File

@@ -233,6 +233,21 @@ class BaseTerminalController: NSWindowController,
return newView
}
/// Move focus to a surface view.
func focusSurface(_ view: Ghostty.SurfaceView) {
// Check if target surface is in our tree
guard surfaceTree.contains(view) else { return }
// Move focus to the target surface and activate the window/app
DispatchQueue.main.async {
Ghostty.moveFocus(to: view)
view.window?.makeKeyAndOrderFront(nil)
if !NSApp.isActive {
NSApp.activate(ignoringOtherApps: true)
}
}
}
/// Called when the surfaceTree variable changed.
///
/// Subclasses should call super first.

View File

@@ -79,7 +79,7 @@ elif [ "$1" != "--update" ]; then
exit 1
fi
zon2nix "$BUILD_ZIG_ZON" --nix "$WORK_DIR/build.zig.zon.nix" --txt "$WORK_DIR/build.zig.zon.txt" --json "$WORK_DIR/build.zig.zon.json" --flatpak "$WORK_DIR/zig-packages.json"
zon2nix "$BUILD_ZIG_ZON" --14 --nix "$WORK_DIR/build.zig.zon.nix" --txt "$WORK_DIR/build.zig.zon.txt" --json "$WORK_DIR/build.zig.zon.json" --flatpak "$WORK_DIR/zig-packages.json"
alejandra --quiet "$WORK_DIR/build.zig.zon.nix"
prettier --log-level warn --write "$WORK_DIR/build.zig.zon.json"
prettier --log-level warn --write "$WORK_DIR/zig-packages.json"
@@ -118,4 +118,3 @@ else
echo -e "OK: flatpak/zig-packages.json updated."
exit 0
fi

View File

@@ -3,6 +3,7 @@
lib,
stdenv,
bashInteractive,
doxygen,
nushell,
appstream,
flatpak-builder,
@@ -89,6 +90,7 @@ in
packages =
[
# For builds
doxygen
jq
llvmPackages_latest.llvm
minisign

View File

@@ -40,7 +40,7 @@
in
stdenv.mkDerivation (finalAttrs: {
pname = "ghostty";
version = "1.2.0";
version = "1.2.1";
# We limit source like this to try and reduce the amount of rebuilds as possible
# thus we only provide the source that is needed for the build

View File

@@ -11,7 +11,7 @@ pub fn build(b: *std.Build) !void {
.optimize = optimize,
});
const imgui = b.dependency("imgui", .{});
const imgui_ = b.lazyDependency("imgui", .{});
const lib = b.addLibrary(.{
.name = "cimgui",
.root_module = b.createModule(.{
@@ -52,7 +52,7 @@ pub fn build(b: *std.Build) !void {
}
}
lib.addIncludePath(imgui.path(""));
if (imgui_) |imgui| lib.addIncludePath(imgui.path(""));
module.addIncludePath(b.path("vendor"));
var flags = std.ArrayList([]const u8).init(b.allocator);
@@ -72,32 +72,33 @@ pub fn build(b: *std.Build) !void {
});
}
lib.addCSourceFile(.{ .file = b.path("vendor/cimgui.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_draw.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_demo.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_widgets.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_tables.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("misc/freetype/imgui_freetype.cpp"), .flags = flags.items });
lib.addCSourceFile(.{
.file = imgui.path("backends/imgui_impl_opengl3.cpp"),
.flags = flags.items,
});
if (target.result.os.tag.isDarwin()) {
if (!target.query.isNative()) {
try @import("apple_sdk").addPaths(b, lib);
}
if (imgui_) |imgui| {
lib.addCSourceFile(.{ .file = b.path("vendor/cimgui.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_draw.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_demo.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_widgets.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_tables.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("misc/freetype/imgui_freetype.cpp"), .flags = flags.items });
lib.addCSourceFile(.{
.file = imgui.path("backends/imgui_impl_metal.mm"),
.file = imgui.path("backends/imgui_impl_opengl3.cpp"),
.flags = flags.items,
});
if (target.result.os.tag == .macos) {
if (target.result.os.tag.isDarwin()) {
if (!target.query.isNative()) {
try @import("apple_sdk").addPaths(b, lib);
}
lib.addCSourceFile(.{
.file = imgui.path("backends/imgui_impl_osx.mm"),
.file = imgui.path("backends/imgui_impl_metal.mm"),
.flags = flags.items,
});
if (target.result.os.tag == .macos) {
lib.addCSourceFile(.{
.file = imgui.path("backends/imgui_impl_osx.mm"),
.flags = flags.items,
});
}
}
}

View File

@@ -10,6 +10,7 @@
// ocornut/imgui
.url = "https://deps.files.ghostty.org/imgui-1220bc6b9daceaf7c8c60f3c3998058045ba0c5c5f48ae255ff97776d9cd8bfc6402.tar.gz",
.hash = "N-V-__8AAH0GaQC8a52s6vfIxg88OZgFgEW6DFxfSK4lX_l3",
.lazy = true,
},
.apple_sdk = .{ .path = "../apple-sdk" },

View File

@@ -10,11 +10,11 @@ pub fn build(b: *std.Build) !void {
.optimize = optimize,
});
const upstream = b.dependency("glslang", .{});
const upstream = b.lazyDependency("glslang", .{});
const lib = try buildGlslang(b, upstream, target, optimize);
b.installArtifact(lib);
module.addIncludePath(upstream.path(""));
if (upstream) |v| module.addIncludePath(v.path(""));
module.addIncludePath(b.path("override"));
if (target.query.isNative()) {
@@ -38,7 +38,7 @@ pub fn build(b: *std.Build) !void {
fn buildGlslang(
b: *std.Build,
upstream: *std.Build.Dependency,
upstream_: ?*std.Build.Dependency,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
) !*std.Build.Step.Compile {
@@ -52,7 +52,7 @@ fn buildGlslang(
});
lib.linkLibC();
lib.linkLibCpp();
lib.addIncludePath(upstream.path(""));
if (upstream_) |upstream| lib.addIncludePath(upstream.path(""));
lib.addIncludePath(b.path("override"));
if (target.result.os.tag.isDarwin()) {
const apple_sdk = @import("apple_sdk");
@@ -66,87 +66,89 @@ fn buildGlslang(
"-fno-sanitize-trap=undefined",
});
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
.files = &.{
// GenericCodeGen
"glslang/GenericCodeGen/CodeGen.cpp",
"glslang/GenericCodeGen/Link.cpp",
// MachineIndependent
//"MachineIndependent/glslang.y",
"glslang/MachineIndependent/glslang_tab.cpp",
"glslang/MachineIndependent/attribute.cpp",
"glslang/MachineIndependent/Constant.cpp",
"glslang/MachineIndependent/iomapper.cpp",
"glslang/MachineIndependent/InfoSink.cpp",
"glslang/MachineIndependent/Initialize.cpp",
"glslang/MachineIndependent/IntermTraverse.cpp",
"glslang/MachineIndependent/Intermediate.cpp",
"glslang/MachineIndependent/ParseContextBase.cpp",
"glslang/MachineIndependent/ParseHelper.cpp",
"glslang/MachineIndependent/PoolAlloc.cpp",
"glslang/MachineIndependent/RemoveTree.cpp",
"glslang/MachineIndependent/Scan.cpp",
"glslang/MachineIndependent/ShaderLang.cpp",
"glslang/MachineIndependent/SpirvIntrinsics.cpp",
"glslang/MachineIndependent/SymbolTable.cpp",
"glslang/MachineIndependent/Versions.cpp",
"glslang/MachineIndependent/intermOut.cpp",
"glslang/MachineIndependent/limits.cpp",
"glslang/MachineIndependent/linkValidate.cpp",
"glslang/MachineIndependent/parseConst.cpp",
"glslang/MachineIndependent/reflection.cpp",
"glslang/MachineIndependent/preprocessor/Pp.cpp",
"glslang/MachineIndependent/preprocessor/PpAtom.cpp",
"glslang/MachineIndependent/preprocessor/PpContext.cpp",
"glslang/MachineIndependent/preprocessor/PpScanner.cpp",
"glslang/MachineIndependent/preprocessor/PpTokens.cpp",
"glslang/MachineIndependent/propagateNoContraction.cpp",
// C Interface
"glslang/CInterface/glslang_c_interface.cpp",
// ResourceLimits
"glslang/ResourceLimits/ResourceLimits.cpp",
"glslang/ResourceLimits/resource_limits_c.cpp",
// SPIRV
"SPIRV/GlslangToSpv.cpp",
"SPIRV/InReadableOrder.cpp",
"SPIRV/Logger.cpp",
"SPIRV/SpvBuilder.cpp",
"SPIRV/SpvPostProcess.cpp",
"SPIRV/doc.cpp",
"SPIRV/disassemble.cpp",
"SPIRV/CInterface/spirv_c_interface.cpp",
},
});
if (target.result.os.tag != .windows) {
if (upstream_) |upstream| {
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
.files = &.{
"glslang/OSDependent/Unix/ossource.cpp",
},
});
} else {
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
.files = &.{
"glslang/OSDependent/Windows/ossource.cpp",
// GenericCodeGen
"glslang/GenericCodeGen/CodeGen.cpp",
"glslang/GenericCodeGen/Link.cpp",
// MachineIndependent
//"MachineIndependent/glslang.y",
"glslang/MachineIndependent/glslang_tab.cpp",
"glslang/MachineIndependent/attribute.cpp",
"glslang/MachineIndependent/Constant.cpp",
"glslang/MachineIndependent/iomapper.cpp",
"glslang/MachineIndependent/InfoSink.cpp",
"glslang/MachineIndependent/Initialize.cpp",
"glslang/MachineIndependent/IntermTraverse.cpp",
"glslang/MachineIndependent/Intermediate.cpp",
"glslang/MachineIndependent/ParseContextBase.cpp",
"glslang/MachineIndependent/ParseHelper.cpp",
"glslang/MachineIndependent/PoolAlloc.cpp",
"glslang/MachineIndependent/RemoveTree.cpp",
"glslang/MachineIndependent/Scan.cpp",
"glslang/MachineIndependent/ShaderLang.cpp",
"glslang/MachineIndependent/SpirvIntrinsics.cpp",
"glslang/MachineIndependent/SymbolTable.cpp",
"glslang/MachineIndependent/Versions.cpp",
"glslang/MachineIndependent/intermOut.cpp",
"glslang/MachineIndependent/limits.cpp",
"glslang/MachineIndependent/linkValidate.cpp",
"glslang/MachineIndependent/parseConst.cpp",
"glslang/MachineIndependent/reflection.cpp",
"glslang/MachineIndependent/preprocessor/Pp.cpp",
"glslang/MachineIndependent/preprocessor/PpAtom.cpp",
"glslang/MachineIndependent/preprocessor/PpContext.cpp",
"glslang/MachineIndependent/preprocessor/PpScanner.cpp",
"glslang/MachineIndependent/preprocessor/PpTokens.cpp",
"glslang/MachineIndependent/propagateNoContraction.cpp",
// C Interface
"glslang/CInterface/glslang_c_interface.cpp",
// ResourceLimits
"glslang/ResourceLimits/ResourceLimits.cpp",
"glslang/ResourceLimits/resource_limits_c.cpp",
// SPIRV
"SPIRV/GlslangToSpv.cpp",
"SPIRV/InReadableOrder.cpp",
"SPIRV/Logger.cpp",
"SPIRV/SpvBuilder.cpp",
"SPIRV/SpvPostProcess.cpp",
"SPIRV/doc.cpp",
"SPIRV/disassemble.cpp",
"SPIRV/CInterface/spirv_c_interface.cpp",
},
});
if (target.result.os.tag != .windows) {
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
.files = &.{
"glslang/OSDependent/Unix/ossource.cpp",
},
});
} else {
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
.files = &.{
"glslang/OSDependent/Windows/ossource.cpp",
},
});
}
lib.installHeadersDirectory(
upstream.path(""),
"",
.{ .include_extensions = &.{".h"} },
);
}
lib.installHeadersDirectory(
upstream.path(""),
"",
.{ .include_extensions = &.{".h"} },
);
return lib;
}

View File

@@ -8,6 +8,7 @@
.glslang = .{
.url = "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz",
.hash = "N-V-__8AABzkUgISeKGgXAzgtutgJsZc0-kkeqBBscJgMkvy",
.lazy = true,
},
.apple_sdk = .{ .path = "../apple-sdk" },

View File

@@ -4,7 +4,7 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const upstream = b.dependency("highway", .{});
const upstream_ = b.lazyDependency("highway", .{});
const module = b.addModule("highway", .{
.root_source_file = b.path("main.zig"),
@@ -21,8 +21,10 @@ pub fn build(b: *std.Build) !void {
.linkage = .static,
});
lib.linkLibCpp();
lib.addIncludePath(upstream.path(""));
module.addIncludePath(upstream.path(""));
if (upstream_) |upstream| {
lib.addIncludePath(upstream.path(""));
module.addIncludePath(upstream.path(""));
}
if (target.result.os.tag.isDarwin()) {
const apple_sdk = @import("apple_sdk");
@@ -74,24 +76,26 @@ pub fn build(b: *std.Build) !void {
}
lib.addCSourceFiles(.{ .flags = flags.items, .files = &.{"bridge.cpp"} });
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
.files = &.{
"hwy/abort.cc",
"hwy/aligned_allocator.cc",
"hwy/nanobenchmark.cc",
"hwy/per_target.cc",
"hwy/print.cc",
"hwy/targets.cc",
"hwy/timer.cc",
},
});
lib.installHeadersDirectory(
upstream.path("hwy"),
"hwy",
.{ .include_extensions = &.{".h"} },
);
if (upstream_) |upstream| {
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
.files = &.{
"hwy/abort.cc",
"hwy/aligned_allocator.cc",
"hwy/nanobenchmark.cc",
"hwy/per_target.cc",
"hwy/print.cc",
"hwy/targets.cc",
"hwy/timer.cc",
},
});
lib.installHeadersDirectory(
upstream.path("hwy"),
"hwy",
.{ .include_extensions = &.{".h"} },
);
}
b.installArtifact(lib);

View File

@@ -8,6 +8,7 @@
.highway = .{
.url = "https://deps.files.ghostty.org/highway-66486a10623fa0d72fe91260f96c892e41aceb06.tar.gz",
.hash = "N-V-__8AAGmZhABbsPJLfbqrh6JTHsXhY6qCaLAQyx25e0XE",
.lazy = true,
},
.apple_sdk = .{ .path = "../apple-sdk" },

View File

@@ -4,7 +4,7 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const upstream = b.dependency("libxml2", .{});
const upstream_ = b.lazyDependency("libxml2", .{});
const lib = b.addLibrary(.{
.name = "xml2",
@@ -16,7 +16,7 @@ pub fn build(b: *std.Build) !void {
});
lib.linkLibC();
lib.addIncludePath(upstream.path("include"));
if (upstream_) |upstream| lib.addIncludePath(upstream.path("include"));
lib.addIncludePath(b.path("override/include"));
if (target.result.os.tag == .windows) {
lib.addIncludePath(b.path("override/config/win32"));
@@ -97,21 +97,23 @@ pub fn build(b: *std.Build) !void {
}
}
lib.addCSourceFiles(.{
.root = upstream.path(""),
.files = srcs,
.flags = flags.items,
});
if (upstream_) |upstream| {
lib.addCSourceFiles(.{
.root = upstream.path(""),
.files = srcs,
.flags = flags.items,
});
lib.installHeader(
b.path("override/include/libxml/xmlversion.h"),
"libxml/xmlversion.h",
);
lib.installHeadersDirectory(
upstream.path("include"),
"",
.{ .include_extensions = &.{".h"} },
);
lib.installHeader(
b.path("override/include/libxml/xmlversion.h"),
"libxml/xmlversion.h",
);
lib.installHeadersDirectory(
upstream.path("include"),
"",
.{ .include_extensions = &.{".h"} },
);
}
b.installArtifact(lib);
}

View File

@@ -7,6 +7,7 @@
.libxml2 = .{
.url = "https://deps.files.ghostty.org/libxml2-2.11.5.tar.gz",
.hash = "N-V-__8AAG3RoQEyRC2Vw7Qoro5SYBf62IHn3HjqtNVY6aWK",
.lazy = true,
},
},
}

View File

@@ -4,16 +4,19 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const upstream = b.dependency("spirv_cross", .{});
const module = b.addModule("spirv_cross", .{ .root_source_file = b.path("main.zig"), .target = target, .optimize = optimize });
const module = b.addModule("spirv_cross", .{ .root_source_file = b.path("main.zig") });
module.addIncludePath(upstream.path(""));
const lib = try buildSpirvCross(b, upstream, target, optimize);
b.installArtifact(lib);
// For dynamic linking, we prefer dynamic linking and to search by
// mode first. Mode first will search all paths for a dynamic library
// before falling back to static.
const dynamic_link_opts: std.Build.Module.LinkSystemLibraryOptions = .{
.preferred_link_mode = .dynamic,
.search_strategy = .mode_first,
};
var test_exe: ?*std.Build.Step.Compile = null;
if (target.query.isNative()) {
const test_exe = b.addTest(.{
test_exe = b.addTest(.{
.name = "test",
.root_module = b.createModule(.{
.root_source_file = b.path("main.zig"),
@@ -21,19 +24,28 @@ pub fn build(b: *std.Build) !void {
.optimize = optimize,
}),
});
test_exe.linkLibrary(lib);
const tests_run = b.addRunArtifact(test_exe);
const tests_run = b.addRunArtifact(test_exe.?);
const test_step = b.step("test", "Run tests");
test_step.dependOn(&tests_run.step);
// Uncomment this if we're debugging tests
// b.installArtifact(test_exe);
// b.installArtifact(test_exe.?);
}
if (b.systemIntegrationOption("spirv-cross", .{})) {
module.linkSystemLibrary("spirv-cross-c-shared", dynamic_link_opts);
if (test_exe) |exe| {
exe.linkSystemLibrary2("spirv-cross-c-shared", dynamic_link_opts);
}
} else {
const lib = try buildSpirvCross(b, module, target, optimize);
b.installArtifact(lib);
if (test_exe) |exe| exe.linkLibrary(lib);
}
}
fn buildSpirvCross(
b: *std.Build,
upstream: *std.Build.Dependency,
module: *std.Build.Module,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
) !*std.Build.Step.Compile {
@@ -62,32 +74,36 @@ fn buildSpirvCross(
"-fno-sanitize-trap=undefined",
});
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
.files = &.{
// Core
"spirv_cross.cpp",
"spirv_parser.cpp",
"spirv_cross_parsed_ir.cpp",
"spirv_cfg.cpp",
if (b.lazyDependency("spirv_cross", .{})) |upstream| {
lib.addIncludePath(upstream.path(""));
module.addIncludePath(upstream.path(""));
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
.files = &.{
// Core
"spirv_cross.cpp",
"spirv_parser.cpp",
"spirv_cross_parsed_ir.cpp",
"spirv_cfg.cpp",
// C
"spirv_cross_c.cpp",
// C
"spirv_cross_c.cpp",
// GLSL
"spirv_glsl.cpp",
// GLSL
"spirv_glsl.cpp",
// MSL
"spirv_msl.cpp",
},
});
// MSL
"spirv_msl.cpp",
},
});
lib.installHeadersDirectory(
upstream.path(""),
"",
.{ .include_extensions = &.{".h"} },
);
lib.installHeadersDirectory(
upstream.path(""),
"",
.{ .include_extensions = &.{".h"} },
);
}
return lib;
}

View File

@@ -8,6 +8,7 @@
.spirv_cross = .{
.url = "https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz",
.hash = "N-V-__8AANb6pwD7O1WG6L5nvD_rNMvnSc9Cpg1ijSlTYywv",
.lazy = true,
},
.apple_sdk = .{ .path = "../apple-sdk" },

View File

@@ -1,40 +0,0 @@
const std = @import("std");
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const module = b.addModule("utf8proc", .{ .root_source_file = .{ .path = "main.zig" } });
const upstream = b.dependency("utf8proc", .{});
const lib = b.addLibrary(.{
.name = "utf8proc",
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
.linkage = .static,
});
lib.linkLibC();
lib.addIncludePath(upstream.path(""));
module.addIncludePath(upstream.path(""));
var flags = std.ArrayList([]const u8).init(b.allocator);
try flags.append("-DUTF8PROC_EXPORTS");
defer flags.deinit();
lib.addCSourceFiles(.{
.root = upstream.path(""),
.files = &.{"utf8proc.c"},
.flags = flags.items,
});
lib.installHeadersDirectoryOptions(.{
.source_dir = upstream.path(""),
.install_dir = .header,
.install_subdir = "",
.include_extensions = &.{".h"},
});
b.installArtifact(lib);
}

View File

@@ -1,11 +0,0 @@
.{
.name = "utf8proc",
.version = "2.8.0",
.paths = .{""},
.dependencies = .{
.utf8proc = .{
.url = "https://github.com/JuliaStrings/utf8proc/archive/refs/tags/v2.8.0.tar.gz",
.hash = "1220056ce228a8c58f1fa66ab778f5c8965e62f720c1d30603c7d534cb7d8a605ad7",
},
},
}

View File

@@ -1,3 +0,0 @@
pub const c = @cImport({
@cInclude("utf8proc.h");
});

View File

@@ -1,20 +0,0 @@
pub const c = @import("c.zig").c;
/// Given a codepoint, return a character width analogous to `wcwidth(codepoint)`,
/// except that a width of 0 is returned for non-printable codepoints
/// instead of -1 as in `wcwidth`.
pub fn charwidth(codepoint: u21) u8 {
return @intCast(c.utf8proc_charwidth(@intCast(codepoint)));
}
/// Given a pair of consecutive codepoints, return whether a grapheme break is
/// permitted between them (as defined by the extended grapheme clusters in UAX#29).
pub fn graphemeBreakStateful(cp1: u21, cp2: u21, state: *i32) bool {
return c.utf8proc_grapheme_break_stateful(
@intCast(cp1),
@intCast(cp2),
state,
);
}
test {}

View File

@@ -131,12 +131,11 @@ which should be filled in accordingly. You can then add your translations
within the newly created translation file.
Afterwards, you need to update the list of known locales within Ghostty's
build system. To do so, open `src/os/i18n.zig` and find the list
of locales under the `locales` variable, then add the full locale name
into the list.
build system. To do so, open `src/os/i18n_locales.zig` and find the list
of locales after the comments, then add the full locale name into the list.
The order matters, so make sure to place your locale in the correct position.
Read the comment above the variable for more details on the order. If you're
Read the comments present in the file for more details on the order. If you're
unsure, place it at the end of the list.
```zig
@@ -146,7 +145,7 @@ const locales = [_][]const u8{
}
```
You should then be able to run `zig build` and see your translations in action.
You should then be able to run `zig build` and see your translations in action!
Before opening a pull request with the new translation file, you should also add
your locale to the `CODEOWNERS` file. Find the `# Localization` section near the

View File

@@ -404,91 +404,6 @@ pub fn getData(self: Command, comptime DT: type) ?*DT {
return if (self.data) |ptr| @ptrCast(@alignCast(ptr)) else null;
}
/// Search for "cmd" in the PATH and return the absolute path. This will
/// always allocate if there is a non-null result. The caller must free the
/// resulting value.
pub fn expandPath(alloc: Allocator, cmd: []const u8) !?[]u8 {
// If the command already contains a slash, then we return it as-is
// because it is assumed to be absolute or relative.
if (std.mem.indexOfScalar(u8, cmd, '/') != null) {
return try alloc.dupe(u8, cmd);
}
const PATH = switch (builtin.os.tag) {
.windows => blk: {
const win_path = std.process.getenvW(std.unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse return null;
const path = try std.unicode.utf16LeToUtf8Alloc(alloc, win_path);
break :blk path;
},
else => std.posix.getenvZ("PATH") orelse return null,
};
defer if (builtin.os.tag == .windows) alloc.free(PATH);
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
var it = std.mem.tokenizeScalar(u8, PATH, std.fs.path.delimiter);
var seen_eacces = false;
while (it.next()) |search_path| {
// We need enough space in our path buffer to store this
const path_len = search_path.len + cmd.len + 1;
if (path_buf.len < path_len) return error.PathTooLong;
// Copy in the full path
@memcpy(path_buf[0..search_path.len], search_path);
path_buf[search_path.len] = std.fs.path.sep;
@memcpy(path_buf[search_path.len + 1 ..][0..cmd.len], cmd);
path_buf[path_len] = 0;
const full_path = path_buf[0..path_len :0];
// Stat it
const f = std.fs.cwd().openFile(
full_path,
.{},
) catch |err| switch (err) {
error.FileNotFound => continue,
error.AccessDenied => {
// Accumulate this and return it later so we can try other
// paths that we have access to.
seen_eacces = true;
continue;
},
else => return err,
};
defer f.close();
const stat = try f.stat();
if (stat.kind != .directory and isExecutable(stat.mode)) {
return try alloc.dupe(u8, full_path);
}
}
if (seen_eacces) return error.AccessDenied;
return null;
}
fn isExecutable(mode: std.fs.File.Mode) bool {
if (builtin.os.tag == .windows) return true;
return mode & 0o0111 != 0;
}
// `uname -n` is the *nix equivalent of `hostname.exe` on Windows
test "expandPath: hostname" {
const executable = if (builtin.os.tag == .windows) "hostname.exe" else "uname";
const path = (try expandPath(testing.allocator, executable)).?;
defer testing.allocator.free(path);
try testing.expect(path.len > executable.len);
}
test "expandPath: does not exist" {
const path = try expandPath(testing.allocator, "thisreallyprobablydoesntexist123");
try testing.expect(path == null);
}
test "expandPath: slash" {
const path = (try expandPath(testing.allocator, "foo/env")).?;
defer testing.allocator.free(path);
try testing.expect(path.len == 7);
}
// Copied from Zig. This is a publicly exported function but there is no
// way to get it from the std package.
fn createNullDelimitedEnvMap(arena: mem.Allocator, env_map: *const EnvMap) ![:null]?[*:0]u8 {

View File

@@ -23,6 +23,7 @@ pub const embedded = @import("apprt/embedded.zig");
pub const surface = @import("apprt/surface.zig");
pub const Action = action.Action;
pub const Runtime = @import("apprt/runtime.zig").Runtime;
pub const Target = action.Target;
pub const ContentScale = structs.ContentScale;
@@ -51,30 +52,6 @@ pub const runtime = switch (build_config.artifact) {
pub const App = runtime.App;
pub const Surface = runtime.Surface;
/// Runtime is the runtime to use for Ghostty. All runtimes do not provide
/// equivalent feature sets.
pub const Runtime = enum {
/// Will not produce an executable at all when `zig build` is called.
/// This is only useful if you're only interested in the lib only (macOS).
none,
/// GTK4. Rich windowed application. This uses a full GObject-based
/// approach to building the application.
gtk,
pub fn default(target: std.Target) Runtime {
return switch (target.os.tag) {
// The Linux and FreeBSD default is GTK because it is a full
// featured application.
.linux, .freebsd => .gtk,
// Otherwise, we do NONE so we don't create an exe and we create
// libghostty. On macOS, Xcode is used to build the app that links
// to libghostty.
else => .none,
};
}
};
test {
_ = Runtime;
_ = runtime;

View File

@@ -42,6 +42,70 @@ const GlobalShortcuts = @import("global_shortcuts.zig").GlobalShortcuts;
const log = std.log.scoped(.gtk_ghostty_application);
/// Function used to funnel GLib/GObject/GTK log messages into Zig's logging
/// system rather than just getting dumped directly to stderr.
fn glibLogWriterFunction(
level: glib.LogLevelFlags,
fields: [*]const glib.LogField,
n_fields: usize,
_: ?*anyopaque,
) callconv(.c) glib.LogWriterOutput {
const glib_log = std.log.scoped(.glib);
var message_: ?[]const u8 = null;
var domain_: ?[]const u8 = null;
for (0..n_fields) |i| {
const field = fields[i];
const k = std.mem.span(field.f_key orelse continue);
const v: []const u8 = v: {
if (field.f_length >= 0) {
const v: [*]const u8 = @ptrCast(field.f_value orelse continue);
break :v v[0..@intCast(field.f_length)];
}
const v: [*:0]const u8 = @ptrCast(field.f_value orelse continue);
break :v std.mem.span(v);
};
if (std.mem.eql(u8, k, "MESSAGE")) {
message_ = v;
continue;
}
if (std.mem.eql(u8, k, "GLIB_DOMAIN")) {
domain_ = v;
continue;
}
}
const message = message_ orelse return .unhandled;
const domain = domain_ orelse "«unknown»";
if (level.level_error) {
glib_log.err("ERROR: {s}: {s}", .{ domain, message });
return .handled;
}
if (level.level_critical) {
glib_log.err("CRITICAL: {s}: {s}", .{ domain, message });
return .handled;
}
if (level.level_warning) {
glib_log.warn("WARNING: {s}: {s}", .{ domain, message });
return .handled;
}
if (level.level_message) {
glib_log.info("MESSAGE: {s}: {s}", .{ domain, message });
return .handled;
}
if (level.level_info) {
glib_log.info("INFO: {s}: {s}", .{ domain, message });
return .handled;
}
if (level.level_debug) {
glib_log.debug("DEBUG: {s}: {s}", .{ domain, message });
return .handled;
}
glib_log.debug("UNKNOWN: {s}: {s}", .{ domain, message });
return .handled;
}
/// The primary entrypoint for the Ghostty GTK application.
///
/// This requires a `ghostty.App` and `ghostty.Config` and takes
@@ -177,6 +241,10 @@ pub const Application = extern struct {
) Allocator.Error!*Self {
const alloc = core_app.alloc;
// Capture GLib/GObject/GTK log messages and funnel them through Zig's
// logging system rather than just getting dumped directly to stderr.
_ = glib.logSetWriterFunc(glibLogWriterFunction, null, null);
// Log our GTK versions
gtk_version.logVersion();
adw_version.logVersion();

View File

@@ -51,6 +51,13 @@ pub const Surface = extern struct {
pub const Tree = datastruct.SplitTree(Self);
pub const properties = struct {
/// This property is set to true when the bell is ringing. Note that
/// this property will only emit a changed signal when there is a
/// full state change. If a bell is ringing and another bell event
/// comes through, the change notification will NOT be emitted.
///
/// If you need to know every scenario the bell is triggered,
/// listen to the `bell` signal instead.
pub const @"bell-ringing" = struct {
pub const name = "bell-ringing";
const impl = gobject.ext.defineProperty(
@@ -296,6 +303,19 @@ pub const Surface = extern struct {
};
pub const signals = struct {
/// Emitted whenever the bell event is received. Unlike the
/// `bell-ringing` property, this is emitted every time the event
/// is received and not just on state changes.
pub const bell = struct {
pub const name = "bell";
pub const connect = impl.connect;
const impl = gobject.ext.defineSignal(
name,
Self,
&.{},
void,
);
};
/// Emitted whenever the surface would like to be closed for any
/// reason.
///
@@ -1674,6 +1694,16 @@ pub const Surface = extern struct {
}
pub fn setBellRinging(self: *Self, ringing: bool) void {
// Prevent duplicate change notifications if the signals we emit
// in this function cause this state to change again.
self.as(gobject.Object).freezeNotify();
defer self.as(gobject.Object).thawNotify();
// Logic around bell reaction happens on every event even if we're
// already in the ringing state.
if (ringing) self.ringBell();
// Property change only happens on actual state change
const priv = self.private();
if (priv.bell_ringing == ringing) return;
priv.bell_ringing = ringing;
@@ -1858,20 +1888,26 @@ pub const Surface = extern struct {
self.as(gtk.Widget).setCursorFromName(name.ptr);
}
fn propBellRinging(
self: *Self,
_: *gobject.ParamSpec,
_: ?*anyopaque,
) callconv(.c) void {
/// Handle bell features that need to happen every time a BEL is received
/// Currently this is audio and system but this could change in the future.
fn ringBell(self: *Self) void {
const priv = self.private();
if (!priv.bell_ringing) return;
// Emit the signal
signals.bell.impl.emit(
self,
null,
.{},
null,
);
// Activate actions if they exist
_ = self.as(gtk.Widget).activateAction("tab.ring-bell", null);
_ = self.as(gtk.Widget).activateAction("win.ring-bell", null);
// Do our sound
const config = if (priv.config) |c| c.get() else return;
// Do our sound
if (config.@"bell-features".audio) audio: {
const config_path = config.@"bell-audio-path" orelse break :audio;
const path, const required = switch (config_path) {
@@ -2859,7 +2895,6 @@ pub const Surface = extern struct {
class.bindTemplateCallback("notify_mouse_hover_url", &propMouseHoverUrl);
class.bindTemplateCallback("notify_mouse_hidden", &propMouseHidden);
class.bindTemplateCallback("notify_mouse_shape", &propMouseShape);
class.bindTemplateCallback("notify_bell_ringing", &propBellRinging);
class.bindTemplateCallback("should_border_be_shown", &closureShouldBorderBeShown);
class.bindTemplateCallback("should_unfocused_split_be_shown", &closureShouldUnfocusedSplitBeShown);
@@ -2884,6 +2919,7 @@ pub const Surface = extern struct {
});
// Signals
signals.bell.impl.register(.{});
signals.@"close-request".impl.register(.{});
signals.@"clipboard-read".impl.register(.{});
signals.@"clipboard-write".impl.register(.{});

View File

@@ -169,7 +169,6 @@ template $GhosttySurface: Adw.Bin {
"surface",
]
notify::bell-ringing => $notify_bell_ringing();
notify::config => $notify_config();
notify::error => $notify_error();
notify::mouse-hover-url => $notify_mouse_hover_url();

29
src/apprt/runtime.zig Normal file
View File

@@ -0,0 +1,29 @@
const std = @import("std");
/// Runtime is the runtime to use for Ghostty. All runtimes do not provide
/// equivalent feature sets.
pub const Runtime = enum {
/// Will not produce an executable at all when `zig build` is called.
/// This is only useful if you're only interested in the lib only (macOS).
none,
/// GTK4. Rich windowed application. This uses a full GObject-based
/// approach to building the application.
gtk,
pub fn default(target: std.Target) Runtime {
return switch (target.os.tag) {
// The Linux and FreeBSD default is GTK because it is a full
// featured application.
.linux, .freebsd => .gtk,
// Otherwise, we do NONE so we don't create an exe and we create
// libghostty. On macOS, Xcode is used to build the app that links
// to libghostty.
else => .none,
};
}
};
test {
_ = Runtime;
}

View File

@@ -10,6 +10,7 @@ const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const Benchmark = @import("Benchmark.zig");
const options = @import("options.zig");
const uucode = @import("uucode");
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
const simd = @import("../simd/main.zig");
const table = @import("../unicode/main.zig").table;
@@ -47,6 +48,9 @@ pub const Mode = enum {
/// Test our lookup table implementation.
table,
/// Using uucode, with custom `width` extension based on `wcwidth`.
uucode,
};
/// Create a new terminal stream handler for the given arguments.
@@ -71,6 +75,7 @@ pub fn benchmark(self: *CodepointWidth) Benchmark {
.wcwidth => stepWcwidth,
.table => stepTable,
.simd => stepSimd,
.uucode => stepUucode,
},
.setupFn = setup,
.teardownFn = teardown,
@@ -180,6 +185,35 @@ fn stepSimd(ptr: *anyopaque) Benchmark.Error!void {
}
}
fn stepUucode(ptr: *anyopaque) Benchmark.Error!void {
const self: *CodepointWidth = @ptrCast(@alignCast(ptr));
const f = self.data_f orelse return;
var r = std.io.bufferedReader(f.reader());
var d: UTF8Decoder = .{};
var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
while (true) {
const n = r.read(&buf) catch |err| {
log.warn("error reading data file err={}", .{err});
return error.BenchmarkFailed;
};
if (n == 0) break; // EOF reached
for (buf[0..n]) |c| {
const cp_, const consumed = d.next(c);
assert(consumed);
if (cp_) |cp| {
// This is the same trick we do in terminal.zig so we
// keep it here.
std.mem.doNotOptimizeAway(if (cp <= 0xFF)
1
else
uucode.get(.width, @intCast(cp)));
}
}
}
}
test CodepointWidth {
const testing = std.testing;
const alloc = testing.allocator;

View File

@@ -8,6 +8,7 @@ const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const Benchmark = @import("Benchmark.zig");
const options = @import("options.zig");
const uucode = @import("uucode");
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
const unicode = @import("../unicode/main.zig");
@@ -38,6 +39,9 @@ pub const Mode = enum {
/// Ghostty's table-based approach.
table,
/// uucode implementation
uucode,
};
/// Create a new terminal stream handler for the given arguments.
@@ -60,6 +64,7 @@ pub fn benchmark(self: *GraphemeBreak) Benchmark {
.stepFn = switch (self.opts.mode) {
.noop => stepNoop,
.table => stepTable,
.uucode => stepUucode,
},
.setupFn = setup,
.teardownFn = teardown,
@@ -133,6 +138,33 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void {
}
}
fn stepUucode(ptr: *anyopaque) Benchmark.Error!void {
const self: *GraphemeBreak = @ptrCast(@alignCast(ptr));
const f = self.data_f orelse return;
var r = std.io.bufferedReader(f.reader());
var d: UTF8Decoder = .{};
var state: uucode.grapheme.BreakState = .default;
var cp1: u21 = 0;
var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
while (true) {
const n = r.read(&buf) catch |err| {
log.warn("error reading data file err={}", .{err});
return error.BenchmarkFailed;
};
if (n == 0) break; // EOF reached
for (buf[0..n]) |c| {
const cp_, const consumed = d.next(c);
assert(consumed);
if (cp_) |cp2| {
std.mem.doNotOptimizeAway(uucode.grapheme.isBreak(cp1, @intCast(cp2), &state));
cp1 = cp2;
}
}
}
}
test GraphemeBreak {
const testing = std.testing;
const alloc = testing.allocator;

View File

@@ -10,7 +10,8 @@ const Allocator = std.mem.Allocator;
const Benchmark = @import("Benchmark.zig");
const options = @import("options.zig");
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
const symbols = @import("../unicode/symbols.zig");
const uucode = @import("uucode");
const symbols_table = @import("../unicode/symbols_table.zig").table;
const log = std.log.scoped(.@"is-symbol-bench");
@@ -21,7 +22,7 @@ data_f: ?std.fs.File = null,
pub const Options = struct {
/// Which test to run.
mode: Mode = .ziglyph,
mode: Mode = .uucode,
/// The data to read as a filepath. If this is "-" then
/// we will read stdin. If this is unset, then we will
@@ -32,8 +33,8 @@ pub const Options = struct {
};
pub const Mode = enum {
/// "Naive" ziglyph implementation.
ziglyph,
/// uucode implementation
uucode,
/// Ghostty's table-based approach.
table,
@@ -57,7 +58,7 @@ pub fn destroy(self: *IsSymbol, alloc: Allocator) void {
pub fn benchmark(self: *IsSymbol) Benchmark {
return .init(self, .{
.stepFn = switch (self.opts.mode) {
.ziglyph => stepZiglyph,
.uucode => stepUucode,
.table => stepTable,
},
.setupFn = setup,
@@ -85,7 +86,7 @@ fn teardown(ptr: *anyopaque) void {
}
}
fn stepZiglyph(ptr: *anyopaque) Benchmark.Error!void {
fn stepUucode(ptr: *anyopaque) Benchmark.Error!void {
const self: *IsSymbol = @ptrCast(@alignCast(ptr));
const f = self.data_f orelse return;
@@ -103,7 +104,7 @@ fn stepZiglyph(ptr: *anyopaque) Benchmark.Error!void {
const cp_, const consumed = d.next(c);
assert(consumed);
if (cp_) |cp| {
std.mem.doNotOptimizeAway(symbols.isSymbol(cp));
std.mem.doNotOptimizeAway(uucode.get(.is_symbol, cp));
}
}
}
@@ -127,7 +128,7 @@ fn stepTable(ptr: *anyopaque) Benchmark.Error!void {
const cp_, const consumed = d.next(c);
assert(consumed);
if (cp_) |cp| {
std.mem.doNotOptimizeAway(symbols.table.get(cp));
std.mem.doNotOptimizeAway(symbols_table.get(cp));
}
}
}

View File

@@ -79,7 +79,7 @@ fn step(ptr: *anyopaque) Benchmark.Error!void {
var p: terminalpkg.Parser = .init();
var buf: [4096]u8 = undefined;
var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
while (true) {
const n = r.read(&buf) catch |err| {
log.warn("error reading data file err={}", .{err});

View File

@@ -115,7 +115,7 @@ fn step(ptr: *anyopaque) Benchmark.Error!void {
const f = self.data_f orelse return;
var r = std.io.bufferedReader(f.reader());
var buf: [4096]u8 = undefined;
var buf: [4096]u8 align(std.atomic.cache_line) = undefined;
while (true) {
const n = r.read(&buf) catch |err| {
log.warn("error reading data file err={}", .{err});

View File

@@ -5,12 +5,13 @@ const Config = @This();
const std = @import("std");
const builtin = @import("builtin");
const apprt = @import("../apprt.zig");
const font = @import("../font/main.zig");
const rendererpkg = @import("../renderer.zig");
const Command = @import("../Command.zig");
const ApprtRuntime = @import("../apprt/runtime.zig").Runtime;
const FontBackend = @import("../font/backend.zig").Backend;
const RendererBackend = @import("../renderer/backend.zig").Backend;
const TerminalBuildOptions = @import("../terminal/build_options.zig").Options;
const XCFramework = @import("GhosttyXCFramework.zig");
const WasmTarget = @import("../os/wasm/target.zig").Target;
const expandPath = @import("../os/path.zig").expand;
const gtk = @import("gtk.zig");
const GitVersion = @import("GitVersion.zig");
@@ -20,7 +21,7 @@ const GitVersion = @import("GitVersion.zig");
/// TODO: When Zig 0.14 is released, derive this from build.zig.zon directly.
/// Until then this MUST match build.zig.zon and should always be the
/// _next_ version to release.
const app_version: std.SemanticVersion = .{ .major = 1, .minor = 2, .patch = 0 };
const app_version: std.SemanticVersion = .{ .major = 1, .minor = 2, .patch = 1 };
/// Standard build configuration options.
optimize: std.builtin.OptimizeMode,
@@ -29,14 +30,15 @@ xcframework_target: XCFramework.Target = .universal,
wasm_target: WasmTarget,
/// Comptime interfaces
app_runtime: apprt.Runtime = .none,
renderer: rendererpkg.Impl = .opengl,
font_backend: font.Backend = .freetype,
app_runtime: ApprtRuntime = .none,
renderer: RendererBackend = .opengl,
font_backend: FontBackend = .freetype,
/// Feature flags
x11: bool = false,
wayland: bool = false,
sentry: bool = true,
simd: bool = true,
i18n: bool = true,
wasm_shared: bool = true,
@@ -127,22 +129,22 @@ pub fn init(b: *std.Build) !Config {
//---------------------------------------------------------------
// Comptime Interfaces
config.font_backend = b.option(
font.Backend,
FontBackend,
"font-backend",
"The font backend to use for discovery and rasterization.",
) orelse font.Backend.default(target.result, wasm_target);
) orelse FontBackend.default(target.result, wasm_target);
config.app_runtime = b.option(
apprt.Runtime,
ApprtRuntime,
"app-runtime",
"The app runtime to use. Not all values supported on all platforms.",
) orelse apprt.Runtime.default(target.result);
) orelse ApprtRuntime.default(target.result);
config.renderer = b.option(
rendererpkg.Impl,
RendererBackend,
"renderer",
"The app runtime to use. Not all values supported on all platforms.",
) orelse rendererpkg.Impl.default(target.result, wasm_target);
) orelse RendererBackend.default(target.result, wasm_target);
//---------------------------------------------------------------
// Feature Flags
@@ -173,6 +175,12 @@ pub fn init(b: *std.Build) !Config {
}
};
config.simd = b.option(
bool,
"simd",
"Build with SIMD-accelerated code paths. Results in significant performance improvements.",
) orelse true;
config.wayland = b.option(
bool,
"gtk-wayland",
@@ -339,7 +347,7 @@ pub fn init(b: *std.Build) !Config {
if (system_package) break :emit_docs true;
// We only default to true if we can find pandoc.
const path = Command.expandPath(b.allocator, "pandoc") catch
const path = expandPath(b.allocator, "pandoc") catch
break :emit_docs false;
defer if (path) |p| b.allocator.free(p);
break :emit_docs path != null;
@@ -453,10 +461,11 @@ pub fn addOptions(self: *const Config, step: *std.Build.Step.Options) !void {
step.addOption(bool, "x11", self.x11);
step.addOption(bool, "wayland", self.wayland);
step.addOption(bool, "sentry", self.sentry);
step.addOption(bool, "simd", self.simd);
step.addOption(bool, "i18n", self.i18n);
step.addOption(apprt.Runtime, "app_runtime", self.app_runtime);
step.addOption(font.Backend, "font_backend", self.font_backend);
step.addOption(rendererpkg.Impl, "renderer", self.renderer);
step.addOption(ApprtRuntime, "app_runtime", self.app_runtime);
step.addOption(FontBackend, "font_backend", self.font_backend);
step.addOption(RendererBackend, "renderer", self.renderer);
step.addOption(ExeEntrypoint, "exe_entrypoint", self.exe_entrypoint);
step.addOption(WasmTarget, "wasm_target", self.wasm_target);
step.addOption(bool, "wasm_shared", self.wasm_shared);
@@ -482,6 +491,24 @@ pub fn addOptions(self: *const Config, step: *std.Build.Step.Options) !void {
);
}
/// Returns the build options for the terminal module. This assumes a
/// Ghostty executable being built. Callers should modify this as needed.
pub fn terminalOptions(self: *const Config) TerminalBuildOptions {
return .{
.artifact = .ghostty,
.simd = self.simd,
.oniguruma = true,
.c_abi = false,
.slow_runtime_safety = switch (self.optimize) {
.Debug => true,
.ReleaseSafe,
.ReleaseSmall,
.ReleaseFast,
=> false,
},
};
}
/// Returns a baseline CPU target retaining all the other CPU configs.
pub fn baselineTarget(self: *const Config) std.Build.ResolvedTarget {
// Set our cpu model as baseline. There may need to be other modifications
@@ -511,9 +538,9 @@ pub fn fromOptions() Config {
.version = options.app_version,
.flatpak = options.flatpak,
.app_runtime = std.meta.stringToEnum(apprt.Runtime, @tagName(options.app_runtime)).?,
.font_backend = std.meta.stringToEnum(font.Backend, @tagName(options.font_backend)).?,
.renderer = std.meta.stringToEnum(rendererpkg.Impl, @tagName(options.renderer)).?,
.app_runtime = std.meta.stringToEnum(ApprtRuntime, @tagName(options.app_runtime)).?,
.font_backend = std.meta.stringToEnum(FontBackend, @tagName(options.font_backend)).?,
.renderer = std.meta.stringToEnum(RendererBackend, @tagName(options.renderer)).?,
.snap = options.snap,
.exe_entrypoint = std.meta.stringToEnum(ExeEntrypoint, @tagName(options.exe_entrypoint)).?,
.wasm_target = std.meta.stringToEnum(WasmTarget, @tagName(options.wasm_target)).?,

View File

@@ -25,11 +25,14 @@ pub fn init(b: *std.Build) !GhosttyFrameData {
});
const run = b.addRunArtifact(exe);
// Both the compressed framedata and the Zig source file
// have to be put in the same directory, since the compressed file
// has to be within the source file's include path.
const dir = run.addOutputDirectoryArg("framedata");
_ = run.addOutputFileArg("framedata.compressed");
return .{
.exe = exe,
.output = run.captureStdOut(),
.output = dir.path(b, "framedata.zig"),
};
}

View File

@@ -4,7 +4,7 @@ const std = @import("std");
const builtin = @import("builtin");
const Config = @import("Config.zig");
const gresource = @import("../apprt/gtk/build/gresource.zig");
const internal_os = @import("../os/main.zig");
const locales = @import("../os/i18n_locales.zig").locales;
const domain = "com.mitchellh.ghostty";
@@ -21,7 +21,7 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyI18n {
var steps = std.ArrayList(*std.Build.Step).init(b.allocator);
defer steps.deinit();
inline for (internal_os.i18n.locales) |locale| {
inline for (locales) |locale| {
// There is no encoding suffix in the LC_MESSAGES path on FreeBSD,
// so we need to remove it from `locale` to have a correct destination string.
// (/usr/local/share/locale/en_AU/LC_MESSAGES)
@@ -155,7 +155,7 @@ fn createUpdateStep(b: *std.Build) !*std.Build.Step {
"po/" ++ domain ++ ".pot",
);
inline for (internal_os.i18n.locales) |locale| {
inline for (locales) |locale| {
const msgmerge = b.addSystemCommand(&.{ "msgmerge", "--quiet", "--no-fuzzy-matching" });
msgmerge.addFileArg(b.path("po/" ++ locale ++ ".po"));
msgmerge.addFileArg(xgettext.captureStdOut());

View File

@@ -0,0 +1,88 @@
const GhosttyLibVt = @This();
const std = @import("std");
const RunStep = std.Build.Step.Run;
const Config = @import("Config.zig");
const GhosttyZig = @import("GhosttyZig.zig");
const SharedDeps = @import("SharedDeps.zig");
const LibtoolStep = @import("LibtoolStep.zig");
const LipoStep = @import("LipoStep.zig");
/// The step that generates the file.
step: *std.Build.Step,
/// The artifact result
artifact: *std.Build.Step.InstallArtifact,
/// The final library file
output: std.Build.LazyPath,
dsym: ?std.Build.LazyPath,
pkg_config: std.Build.LazyPath,
pub fn initShared(
b: *std.Build,
zig: *const GhosttyZig,
) !GhosttyLibVt {
const target = zig.vt.resolved_target.?;
const lib = b.addSharedLibrary(.{
.name = "ghostty-vt",
.root_module = zig.vt_c,
.version = std.SemanticVersion{ .major = 0, .minor = 1, .patch = 0 },
});
lib.installHeader(
b.path("include/ghostty/vt.h"),
"ghostty/vt.h",
);
// Get our debug symbols
const dsymutil: ?std.Build.LazyPath = dsymutil: {
if (!target.result.os.tag.isDarwin()) {
break :dsymutil null;
}
const dsymutil = RunStep.create(b, "dsymutil");
dsymutil.addArgs(&.{"dsymutil"});
dsymutil.addFileArg(lib.getEmittedBin());
dsymutil.addArgs(&.{"-o"});
const output = dsymutil.addOutputFileArg("libghostty-vt.dSYM");
break :dsymutil output;
};
// pkg-config
const pc: std.Build.LazyPath = pc: {
const wf = b.addWriteFiles();
break :pc wf.add("libghostty-vt.pc", b.fmt(
\\prefix={s}
\\includedir=${{prefix}}/include
\\libdir=${{prefix}}/lib
\\
\\Name: libghostty-vt
\\URL: https://github.com/ghostty-org/ghostty
\\Description: Ghostty VT library
\\Version: 0.1.0
\\Cflags: -I${{includedir}}
\\Libs: -L${{libdir}} -lghostty-vt
, .{b.install_prefix}));
};
return .{
.step = &lib.step,
.artifact = b.addInstallArtifact(lib, .{}),
.output = lib.getEmittedBin(),
.dsym = dsymutil,
.pkg_config = pc,
};
}
pub fn install(
self: *const GhosttyLibVt,
step: *std.Build.Step,
) void {
const b = step.owner;
step.dependOn(&self.artifact.step);
step.dependOn(&b.addInstallFileWithDir(
self.pkg_config,
.prefix,
"share/pkgconfig/libghostty-vt.pc",
).step);
}

View File

@@ -5,9 +5,6 @@ const builtin = @import("builtin");
const assert = std.debug.assert;
const buildpkg = @import("main.zig");
const Config = @import("Config.zig");
const config_vim = @import("../config/vim.zig");
const config_sublime_syntax = @import("../config/sublime_syntax.zig");
const terminfo = @import("../terminfo/main.zig");
const RunStep = std.Build.Step.Run;
steps: []*std.Build.Step,
@@ -16,6 +13,19 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
var steps = std.ArrayList(*std.Build.Step).init(b.allocator);
errdefer steps.deinit();
// This is the exe used to generate some build data.
const build_data_exe = b.addExecutable(.{
.name = "ghostty-build-data",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main_build_data.zig"),
.target = b.graph.host,
.strip = false,
.omit_frame_pointer = false,
.unwind_tables = .sync,
}),
});
build_data_exe.linkLibC();
// Terminfo
terminfo: {
const os_tag = cfg.target.result.os.tag;
@@ -25,13 +35,10 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
"terminfo";
// Encode our terminfo
var str = std.ArrayList(u8).init(b.allocator);
defer str.deinit();
try terminfo.ghostty.encode(str.writer());
// Write it
var wf = b.addWriteFiles();
const source = wf.add("ghostty.terminfo", str.items);
const run = b.addRunArtifact(build_data_exe);
run.addArg("+terminfo");
const wf = b.addWriteFiles();
const source = wf.addCopyFile(run.captureStdOut(), "ghostty.terminfo");
if (cfg.emit_terminfo) {
const source_install = b.addInstallFile(
@@ -130,8 +137,10 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
// Fish shell completions
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+fish");
const wf = b.addWriteFiles();
_ = wf.add("ghostty.fish", buildpkg.fish_completions);
_ = wf.addCopyFile(run.captureStdOut(), "ghostty.fish");
const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(),
@@ -143,8 +152,10 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
// zsh shell completions
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+zsh");
const wf = b.addWriteFiles();
_ = wf.add("_ghostty", buildpkg.zsh_completions);
_ = wf.addCopyFile(run.captureStdOut(), "_ghostty");
const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(),
@@ -156,8 +167,10 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
// bash shell completions
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+bash");
const wf = b.addWriteFiles();
_ = wf.add("ghostty.bash", buildpkg.bash_completions);
_ = wf.addCopyFile(run.captureStdOut(), "ghostty.bash");
const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(),
@@ -167,39 +180,44 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
try steps.append(&install_step.step);
}
// Vim plugin
// Vim and Neovim plugin
{
const wf = b.addWriteFiles();
_ = wf.add("syntax/ghostty.vim", config_vim.syntax);
_ = wf.add("ftdetect/ghostty.vim", config_vim.ftdetect);
_ = wf.add("ftplugin/ghostty.vim", config_vim.ftplugin);
_ = wf.add("compiler/ghostty.vim", config_vim.compiler);
const install_step = b.addInstallDirectory(.{
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+vim-syntax");
_ = wf.addCopyFile(run.captureStdOut(), "syntax/ghostty.vim");
}
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+vim-ftdetect");
_ = wf.addCopyFile(run.captureStdOut(), "ftdetect/ghostty.vim");
}
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+vim-ftplugin");
_ = wf.addCopyFile(run.captureStdOut(), "ftplugin/ghostty.vim");
}
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+vim-compiler");
_ = wf.addCopyFile(run.captureStdOut(), "compiler/ghostty.vim");
}
const vim_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(),
.install_dir = .prefix,
.install_subdir = "share/vim/vimfiles",
});
try steps.append(&install_step.step);
}
try steps.append(&vim_step.step);
// Neovim plugin
// This is just a copy-paste of the Vim plugin, but using a Neovim subdir.
// By default, Neovim doesn't look inside share/vim/vimfiles. Some distros
// configure it to do that however. Fedora, does not as a counterexample.
{
const wf = b.addWriteFiles();
_ = wf.add("syntax/ghostty.vim", config_vim.syntax);
_ = wf.add("ftdetect/ghostty.vim", config_vim.ftdetect);
_ = wf.add("ftplugin/ghostty.vim", config_vim.ftplugin);
_ = wf.add("compiler/ghostty.vim", config_vim.compiler);
const install_step = b.addInstallDirectory(.{
const neovim_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(),
.install_dir = .prefix,
.install_subdir = "share/nvim/site",
});
try steps.append(&install_step.step);
try steps.append(&neovim_step.step);
}
// Sublime syntax highlighting for bat cli tool
@@ -209,8 +227,10 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
// the config file within the '~.config/bat' directory
// (ex: --map-syntax "/Users/user/.config/ghostty/config:Ghostty Config").
{
const run = b.addRunArtifact(build_data_exe);
run.addArg("+sublime");
const wf = b.addWriteFiles();
_ = wf.add("ghostty.sublime-syntax", config_sublime_syntax.syntax);
_ = wf.addCopyFile(run.captureStdOut(), "ghostty.sublime-syntax");
const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(),

82
src/build/GhosttyZig.zig Normal file
View File

@@ -0,0 +1,82 @@
//! GhosttyZig generates the Zig modules that Ghostty exports
//! for downstream usage.
const GhosttyZig = @This();
const std = @import("std");
const Config = @import("Config.zig");
const SharedDeps = @import("SharedDeps.zig");
const TerminalBuildOptions = @import("../terminal/build_options.zig").Options;
/// The `_c`-suffixed modules are built with the C ABI enabled.
vt: *std.Build.Module,
vt_c: *std.Build.Module,
pub fn init(
b: *std.Build,
cfg: *const Config,
deps: *const SharedDeps,
) !GhosttyZig {
// Terminal module build options
var vt_options = cfg.terminalOptions();
vt_options.artifact = .lib;
// We presently don't allow Oniguruma in our Zig module at all.
// We should expose this as a build option in the future so we can
// conditionally do this.
vt_options.oniguruma = false;
return .{
.vt = try initVt(
"ghostty-vt",
b,
cfg,
deps,
vt_options,
),
.vt_c = try initVt(
"ghostty-vt-c",
b,
cfg,
deps,
options: {
var dup = vt_options;
dup.c_abi = true;
break :options dup;
},
),
};
}
fn initVt(
name: []const u8,
b: *std.Build,
cfg: *const Config,
deps: *const SharedDeps,
vt_options: TerminalBuildOptions,
) !*std.Build.Module {
// General build options
const general_options = b.addOptions();
try cfg.addOptions(general_options);
const vt = b.addModule(name, .{
.root_source_file = b.path("src/lib_vt.zig"),
.target = cfg.target,
.optimize = cfg.optimize,
// SIMD require libc/libcpp (both) but otherwise we don't care.
.link_libc = if (cfg.simd) true else null,
.link_libcpp = if (cfg.simd) true else null,
});
vt.addOptions("build_options", general_options);
vt_options.add(b, vt);
// We always need unicode tables
deps.unicode_tables.addModuleImport(vt);
// If SIMD is enabled, add all our SIMD dependencies.
if (cfg.simd) {
try SharedDeps.addSimd(b, vt, null);
}
return vt;
}

View File

@@ -31,9 +31,14 @@ pub fn init(b: *std.Build, cfg: *const Config) !HelpStrings {
exe.root_module.addOptions("build_options", options);
const help_run = b.addRunArtifact(exe);
// Generated Zig files have to end with .zig
const wf = b.addWriteFiles();
const output = wf.addCopyFile(help_run.captureStdOut(), "helpgen.zig");
return .{
.exe = exe,
.output = help_run.captureStdOut(),
.output = output,
};
}

View File

@@ -1,6 +1,8 @@
const SharedDeps = @This();
const std = @import("std");
const builtin = @import("builtin");
const Config = @import("Config.zig");
const HelpStrings = @import("HelpStrings.zig");
const MetallibStep = @import("MetallibStep.zig");
@@ -15,16 +17,26 @@ help_strings: HelpStrings,
metallib: ?*MetallibStep,
unicode_tables: UnicodeTables,
framedata: GhosttyFrameData,
uucode_tables: std.Build.LazyPath,
/// Used to keep track of a list of file sources.
pub const LazyPathList = std.ArrayList(std.Build.LazyPath);
pub fn init(b: *std.Build, cfg: *const Config) !SharedDeps {
const uucode_tables = blk: {
const uucode = b.dependency("uucode", .{
.build_config_path = b.path("src/build/uucode_config.zig"),
});
break :blk uucode.namedLazyPath("tables.zig");
};
var result: SharedDeps = .{
.config = cfg,
.help_strings = try .init(b, cfg),
.unicode_tables = try .init(b),
.unicode_tables = try .init(b, uucode_tables),
.framedata = try .init(b),
.uucode_tables = uucode_tables,
// Setup by retarget
.options = undefined,
@@ -104,9 +116,25 @@ pub fn add(
var static_libs = LazyPathList.init(b.allocator);
errdefer static_libs.deinit();
// WARNING: This is a hack!
// If we're cross-compiling to Darwin then we don't add any deps.
// We don't support cross-compiling to Darwin but due to the way
// lazy dependencies work with Zig, we call this function. So we just
// bail. The build will fail but the build would've failed anyways.
// And this lets other non-platform-specific targets like `lib-vt`
// cross-compile properly.
if (!builtin.target.os.tag.isDarwin() and
self.config.target.result.os.tag.isDarwin())
{
return static_libs;
}
// Every exe gets build options populated
step.root_module.addOptions("build_options", self.options);
// Every exe needs the terminal options
self.config.terminalOptions().add(b, step.root_module);
// Freetype
_ = b.systemIntegrationOption("freetype", .{}); // Shows it in help
if (self.config.font_backend.hasFreetype()) {
@@ -257,7 +285,7 @@ pub fn add(
spirv_cross_dep.module("spirv_cross"),
);
if (b.systemIntegrationOption("spirv-cross", .{})) {
step.linkSystemLibrary2("spirv-cross", dynamic_link_opts);
step.linkSystemLibrary2("spirv-cross-c-shared", dynamic_link_opts);
} else {
step.linkLibrary(spirv_cross_dep.artifact("spirv_cross"));
try static_libs.append(
@@ -266,21 +294,6 @@ pub fn add(
}
}
// Simdutf
if (b.systemIntegrationOption("simdutf", .{})) {
step.linkSystemLibrary2("simdutf", dynamic_link_opts);
} else {
if (b.lazyDependency("simdutf", .{
.target = target,
.optimize = optimize,
})) |simdutf_dep| {
step.linkLibrary(simdutf_dep.artifact("simdutf"));
try static_libs.append(
simdutf_dep.artifact("simdutf").getEmittedBin(),
);
}
}
// Sentry
if (self.config.sentry) {
if (b.lazyDependency("sentry", .{
@@ -309,6 +322,13 @@ pub fn add(
}
}
// Simd
if (self.config.simd) try addSimd(
b,
step.root_module,
&static_libs,
);
// Wasm we do manually since it is such a different build.
if (step.rootModuleTarget().cpu.arch == .wasm32) {
if (b.lazyDependency("zig_js", .{
@@ -343,35 +363,8 @@ pub fn add(
step.addIncludePath(b.path("src/apprt/gtk"));
}
// C++ files
// libcpp is required for various dependencies
step.linkLibCpp();
step.addIncludePath(b.path("src"));
{
// From hwy/detect_targets.h
const HWY_AVX3_SPR: c_int = 1 << 4;
const HWY_AVX3_ZEN4: c_int = 1 << 6;
const HWY_AVX3_DL: c_int = 1 << 7;
const HWY_AVX3: c_int = 1 << 8;
// Zig 0.13 bug: https://github.com/ziglang/zig/issues/20414
// To workaround this we just disable AVX512 support completely.
// The performance difference between AVX2 and AVX512 is not
// significant for our use case and AVX512 is very rare on consumer
// hardware anyways.
const HWY_DISABLED_TARGETS: c_int = HWY_AVX3_SPR | HWY_AVX3_ZEN4 | HWY_AVX3_DL | HWY_AVX3;
step.addCSourceFiles(.{
.files = &.{
"src/simd/base64.cpp",
"src/simd/codepoint_width.cpp",
"src/simd/index_of.cpp",
"src/simd/vt.cpp",
},
.flags = if (step.rootModuleTarget().cpu.arch == .x86_64) &.{
b.fmt("-DHWY_DISABLED_TARGETS={}", .{HWY_DISABLED_TARGETS}),
} else &.{},
});
}
// We always require the system SDK so that our system headers are available.
// This makes things like `os/log.h` available for cross-compiling.
@@ -410,11 +403,13 @@ pub fn add(
})) |dep| {
step.root_module.addImport("z2d", dep.module("z2d"));
}
if (b.lazyDependency("ziglyph", .{
if (b.lazyDependency("uucode", .{
.target = target,
.optimize = optimize,
.tables_path = self.uucode_tables,
.build_config_path = b.path("src/build/uucode_config.zig"),
})) |dep| {
step.root_module.addImport("ziglyph", dep.module("ziglyph"));
step.root_module.addImport("uucode", dep.module("uucode"));
}
if (b.lazyDependency("zf", .{
.target = target,
@@ -481,59 +476,43 @@ pub fn add(
try static_libs.append(cimgui_dep.artifact("cimgui").getEmittedBin());
}
// Highway
if (b.lazyDependency("highway", .{
.target = target,
.optimize = optimize,
})) |highway_dep| {
step.linkLibrary(highway_dep.artifact("highway"));
try static_libs.append(highway_dep.artifact("highway").getEmittedBin());
}
// utfcpp - This is used as a dependency on our hand-written C++ code
if (b.lazyDependency("utfcpp", .{
.target = target,
.optimize = optimize,
})) |utfcpp_dep| {
step.linkLibrary(utfcpp_dep.artifact("utfcpp"));
try static_libs.append(utfcpp_dep.artifact("utfcpp").getEmittedBin());
}
// Fonts
{
// JetBrains Mono
const jb_mono = b.dependency("jetbrains_mono", .{});
step.root_module.addAnonymousImport(
"jetbrains_mono_regular",
.{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Regular.ttf") },
);
step.root_module.addAnonymousImport(
"jetbrains_mono_bold",
.{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Bold.ttf") },
);
step.root_module.addAnonymousImport(
"jetbrains_mono_italic",
.{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Italic.ttf") },
);
step.root_module.addAnonymousImport(
"jetbrains_mono_bold_italic",
.{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-BoldItalic.ttf") },
);
step.root_module.addAnonymousImport(
"jetbrains_mono_variable",
.{ .root_source_file = jb_mono.path("fonts/variable/JetBrainsMono[wght].ttf") },
);
step.root_module.addAnonymousImport(
"jetbrains_mono_variable_italic",
.{ .root_source_file = jb_mono.path("fonts/variable/JetBrainsMono-Italic[wght].ttf") },
);
if (b.lazyDependency("jetbrains_mono", .{})) |jb_mono| {
step.root_module.addAnonymousImport(
"jetbrains_mono_regular",
.{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Regular.ttf") },
);
step.root_module.addAnonymousImport(
"jetbrains_mono_bold",
.{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Bold.ttf") },
);
step.root_module.addAnonymousImport(
"jetbrains_mono_italic",
.{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Italic.ttf") },
);
step.root_module.addAnonymousImport(
"jetbrains_mono_bold_italic",
.{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-BoldItalic.ttf") },
);
step.root_module.addAnonymousImport(
"jetbrains_mono_variable",
.{ .root_source_file = jb_mono.path("fonts/variable/JetBrainsMono[wght].ttf") },
);
step.root_module.addAnonymousImport(
"jetbrains_mono_variable_italic",
.{ .root_source_file = jb_mono.path("fonts/variable/JetBrainsMono-Italic[wght].ttf") },
);
}
// Symbols-only nerd font
const nf_symbols = b.dependency("nerd_fonts_symbols_only", .{});
step.root_module.addAnonymousImport(
"nerd_fonts_symbols_only",
.{ .root_source_file = nf_symbols.path("SymbolsNerdFont-Regular.ttf") },
);
if (b.lazyDependency("nerd_fonts_symbols_only", .{})) |nf_symbols| {
step.root_module.addAnonymousImport(
"nerd_fonts_symbols_only",
.{ .root_source_file = nf_symbols.path("SymbolsNerdFont-Regular.ttf") },
);
}
}
// If we're building an exe then we have additional dependencies.
@@ -615,17 +594,20 @@ fn addGtkNg(
"plasma_wayland_protocols",
.{},
);
const zig_wayland_import_ = b.lazyImport(
@import("../../build.zig"),
"zig_wayland",
);
const zig_wayland_dep_ = b.lazyDependency("zig_wayland", .{});
// Unwrap or return, there are no more dependencies below.
const wayland_dep = wayland_dep_ orelse break :wayland;
const wayland_protocols_dep = wayland_protocols_dep_ orelse break :wayland;
const plasma_wayland_protocols_dep = plasma_wayland_protocols_dep_ orelse break :wayland;
const zig_wayland_import = zig_wayland_import_ orelse break :wayland;
const zig_wayland_dep = zig_wayland_dep_ orelse break :wayland;
// Note that zig_wayland cannot be lazy because lazy dependencies
// can't be imported since they don't exist and imports are
// resolved at compile time of the build.
const zig_wayland_dep = b.dependency("zig_wayland", .{});
const Scanner = @import("zig_wayland").Scanner;
const Scanner = zig_wayland_import.Scanner;
const scanner = Scanner.create(zig_wayland_dep.builder, .{
.wayland_xml = wayland_dep.path("protocol/wayland.xml"),
.wayland_protocols = wayland_protocols_dep.path(""),
@@ -695,6 +677,79 @@ fn addGtkNg(
}
}
/// Add only the dependencies required for `Config.simd` enbled. This also
/// adds all the simd source files for compilation.
pub fn addSimd(
b: *std.Build,
m: *std.Build.Module,
static_libs: ?*LazyPathList,
) !void {
const target = m.resolved_target.?;
const optimize = m.optimize.?;
// Simdutf
if (b.systemIntegrationOption("simdutf", .{})) {
m.linkSystemLibrary("simdutf", dynamic_link_opts);
} else {
if (b.lazyDependency("simdutf", .{
.target = target,
.optimize = optimize,
})) |simdutf_dep| {
m.linkLibrary(simdutf_dep.artifact("simdutf"));
if (static_libs) |v| try v.append(
simdutf_dep.artifact("simdutf").getEmittedBin(),
);
}
}
// Highway
if (b.lazyDependency("highway", .{
.target = target,
.optimize = optimize,
})) |highway_dep| {
m.linkLibrary(highway_dep.artifact("highway"));
if (static_libs) |v| try v.append(highway_dep.artifact("highway").getEmittedBin());
}
// utfcpp - This is used as a dependency on our hand-written C++ code
if (b.lazyDependency("utfcpp", .{
.target = target,
.optimize = optimize,
})) |utfcpp_dep| {
m.linkLibrary(utfcpp_dep.artifact("utfcpp"));
if (static_libs) |v| try v.append(utfcpp_dep.artifact("utfcpp").getEmittedBin());
}
// SIMD C++ files
m.addIncludePath(b.path("src"));
{
// From hwy/detect_targets.h
const HWY_AVX3_SPR: c_int = 1 << 4;
const HWY_AVX3_ZEN4: c_int = 1 << 6;
const HWY_AVX3_DL: c_int = 1 << 7;
const HWY_AVX3: c_int = 1 << 8;
// Zig 0.13 bug: https://github.com/ziglang/zig/issues/20414
// To workaround this we just disable AVX512 support completely.
// The performance difference between AVX2 and AVX512 is not
// significant for our use case and AVX512 is very rare on consumer
// hardware anyways.
const HWY_DISABLED_TARGETS: c_int = HWY_AVX3_SPR | HWY_AVX3_ZEN4 | HWY_AVX3_DL | HWY_AVX3;
m.addCSourceFiles(.{
.files = &.{
"src/simd/base64.cpp",
"src/simd/codepoint_width.cpp",
"src/simd/index_of.cpp",
"src/simd/vt.cpp",
},
.flags = if (target.result.cpu.arch == .x86_64) &.{
b.fmt("-DHWY_DISABLED_TARGETS={}", .{HWY_DISABLED_TARGETS}),
} else &.{},
});
}
}
/// Creates the resources that can be prebuilt for our dist build.
pub fn gtkNgDistResources(
b: *std.Build,

View File

@@ -11,11 +11,11 @@ symbols_exe: *std.Build.Step.Compile,
props_output: std.Build.LazyPath,
symbols_output: std.Build.LazyPath,
pub fn init(b: *std.Build) !UnicodeTables {
pub fn init(b: *std.Build, uucode_tables: std.Build.LazyPath) !UnicodeTables {
const props_exe = b.addExecutable(.{
.name = "props-unigen",
.root_module = b.createModule(.{
.root_source_file = b.path("src/unicode/props.zig"),
.root_source_file = b.path("src/unicode/props_uucode.zig"),
.target = b.graph.host,
.strip = false,
.omit_frame_pointer = false,
@@ -26,7 +26,7 @@ pub fn init(b: *std.Build) !UnicodeTables {
const symbols_exe = b.addExecutable(.{
.name = "symbols-unigen",
.root_module = b.createModule(.{
.root_source_file = b.path("src/unicode/symbols.zig"),
.root_source_file = b.path("src/unicode/symbols_uucode.zig"),
.target = b.graph.host,
.strip = false,
.omit_frame_pointer = false,
@@ -34,36 +34,48 @@ pub fn init(b: *std.Build) !UnicodeTables {
}),
});
if (b.lazyDependency("ziglyph", .{
if (b.lazyDependency("uucode", .{
.target = b.graph.host,
})) |ziglyph_dep| {
.tables_path = uucode_tables,
.build_config_path = b.path("src/build/uucode_config.zig"),
})) |dep| {
inline for (&.{ props_exe, symbols_exe }) |exe| {
exe.root_module.addImport(
"ziglyph",
ziglyph_dep.module("ziglyph"),
);
exe.root_module.addImport("uucode", dep.module("uucode"));
}
}
const props_run = b.addRunArtifact(props_exe);
const symbols_run = b.addRunArtifact(symbols_exe);
// Generated Zig files have to end with .zig
const wf = b.addWriteFiles();
const props_output = wf.addCopyFile(props_run.captureStdOut(), "props.zig");
const symbols_output = wf.addCopyFile(symbols_run.captureStdOut(), "symbols.zig");
return .{
.props_exe = props_exe,
.symbols_exe = symbols_exe,
.props_output = props_run.captureStdOut(),
.symbols_output = symbols_run.captureStdOut(),
.props_output = props_output,
.symbols_output = symbols_output,
};
}
/// Add the "unicode_tables" import.
pub fn addImport(self: *const UnicodeTables, step: *std.Build.Step.Compile) void {
self.props_output.addStepDependencies(&step.step);
step.root_module.addAnonymousImport("unicode_tables", .{
self.symbols_output.addStepDependencies(&step.step);
self.addModuleImport(step.root_module);
}
/// Add the "unicode_tables" import to a module.
pub fn addModuleImport(
self: *const UnicodeTables,
module: *std.Build.Module,
) void {
module.addAnonymousImport("unicode_tables", .{
.root_source_file = self.props_output,
});
self.symbols_output.addStepDependencies(&step.step);
step.root_module.addAnonymousImport("symbols_tables", .{
module.addAnonymousImport("symbols_tables", .{
.root_source_file = self.symbols_output,
});
}

View File

@@ -0,0 +1,33 @@
#--------------------------------------------------------------------
# Generate documentation with Doxygen
#--------------------------------------------------------------------
FROM ubuntu:24.04 AS builder
# Build argument for noindex header
ARG ADD_NOINDEX_HEADER=false
RUN apt-get update && apt-get install -y \
doxygen \
graphviz \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /ghostty
COPY include/ ./include/
COPY Doxyfile ./
RUN mkdir -p zig-out/share/ghostty/doc/libghostty
RUN doxygen
#--------------------------------------------------------------------
# Host the static HTML
#--------------------------------------------------------------------
FROM nginx:alpine AS runtime
# Pass build arg to runtime stage
ARG ADD_NOINDEX_HEADER=false
ENV ADD_NOINDEX_HEADER=$ADD_NOINDEX_HEADER
# Copy documentation and entrypoint script
COPY --from=builder /ghostty/zig-out/share/ghostty/doc/libghostty /usr/share/nginx/html
COPY src/build/docker/lib-c-docs/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 80
CMD ["/entrypoint.sh"]

View File

@@ -0,0 +1,16 @@
#!/bin/sh
if [ "$ADD_NOINDEX_HEADER" = "true" ]; then
cat > /etc/nginx/conf.d/noindex.conf << 'EOF'
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html;
add_header X-Robots-Tag "noindex, nofollow" always;
}
}
EOF
# Remove default server config
rm -f /etc/nginx/conf.d/default.conf
fi
exec nginx -g "daemon off;"

View File

@@ -9,12 +9,12 @@ pub fn main() !void {
// Skip the exe name
_ = arg_iter.skip();
const output_path = arg_iter.next() orelse return error.MissingOutputPath;
const out_dir_path = arg_iter.next() orelse return error.MissingOutputPath;
const compressed_out = "framedata.compressed";
const zig_out = "framedata.zig";
const out_dir_path = fs.path.dirname(output_path) orelse return error.InvalidOutputPath;
const out_dir = try fs.cwd().openDir(out_dir_path, .{});
const compressed_file = try out_dir.createFile(fs.path.basename(output_path), .{});
const compressed_file = try out_dir.createFile(compressed_out, .{});
// Join the frames with a null byte. We'll split on this later
const all_frames = try std.mem.join(gpa.allocator(), "\x01", &frames);
@@ -23,13 +23,15 @@ pub fn main() !void {
const reader = fbs.reader();
try std.compress.flate.compress(reader, compressed_file.writer(), .{});
const stdout = std.io.getStdOut().writer();
const compressed_path = try std.fs.path.join(gpa.allocator(), &.{ out_dir_path, compressed_out });
try stdout.print(
const zig_file = try out_dir.createFile(zig_out, .{});
try zig_file.writer().print(
\\//! This file is auto-generated. Do not edit.
\\
\\pub const compressed = @embedFile("{s}");
, .{output_path});
, .{compressed_path});
}
const frames = [_][]const u8{

View File

@@ -13,11 +13,13 @@ pub const GhosttyDocs = @import("GhosttyDocs.zig");
pub const GhosttyExe = @import("GhosttyExe.zig");
pub const GhosttyFrameData = @import("GhosttyFrameData.zig");
pub const GhosttyLib = @import("GhosttyLib.zig");
pub const GhosttyLibVt = @import("GhosttyLibVt.zig");
pub const GhosttyResources = @import("GhosttyResources.zig");
pub const GhosttyI18n = @import("GhosttyI18n.zig");
pub const GhosttyXcodebuild = @import("GhosttyXcodebuild.zig");
pub const GhosttyXCFramework = @import("GhosttyXCFramework.zig");
pub const GhosttyWebdata = @import("GhosttyWebdata.zig");
pub const GhosttyZig = @import("GhosttyZig.zig");
pub const HelpStrings = @import("HelpStrings.zig");
pub const SharedDeps = @import("SharedDeps.zig");
pub const UnicodeTables = @import("UnicodeTables.zig");
@@ -28,10 +30,5 @@ pub const LipoStep = @import("LipoStep.zig");
pub const MetallibStep = @import("MetallibStep.zig");
pub const XCFrameworkStep = @import("XCFrameworkStep.zig");
// Shell completions
pub const fish_completions = @import("fish_completions.zig").completions;
pub const zsh_completions = @import("zsh_completions.zig").completions;
pub const bash_completions = @import("bash_completions.zig").completions;
// Helpers
pub const requireZig = @import("zig.zig").requireZig;

View File

@@ -0,0 +1,81 @@
const std = @import("std");
const config = @import("config.zig");
const config_x = @import("config.x.zig");
const d = config.default;
const wcwidth = config_x.wcwidth;
const Allocator = std.mem.Allocator;
fn computeWidth(
alloc: std.mem.Allocator,
cp: u21,
data: anytype,
backing: anytype,
tracking: anytype,
) Allocator.Error!void {
_ = alloc;
_ = cp;
_ = backing;
_ = tracking;
data.width = @intCast(@min(2, @max(0, data.wcwidth)));
}
const width = config.Extension{
.inputs = &.{"wcwidth"},
.compute = &computeWidth,
.fields = &.{
.{ .name = "width", .type = u2 },
},
};
fn computeIsSymbol(
alloc: Allocator,
cp: u21,
data: anytype,
backing: anytype,
tracking: anytype,
) Allocator.Error!void {
_ = alloc;
_ = cp;
_ = backing;
_ = tracking;
const block = data.block;
data.is_symbol = data.general_category == .other_private_use or
block == .dingbats or
block == .emoticons or
block == .miscellaneous_symbols or
block == .enclosed_alphanumerics or
block == .enclosed_alphanumeric_supplement or
block == .miscellaneous_symbols_and_pictographs or
block == .transport_and_map_symbols;
}
const is_symbol = config.Extension{
.inputs = &.{ "block", "general_category" },
.compute = &computeIsSymbol,
.fields = &.{
.{ .name = "is_symbol", .type = bool },
},
};
pub const tables = [_]config.Table{
.{
.name = "runtime",
.extensions = &.{},
.fields = &.{
d.field("is_emoji_presentation"),
d.field("case_folding_full"),
},
},
.{
.name = "buildtime",
.extensions = &.{ wcwidth, width, is_symbol },
.fields = &.{
width.field("width"),
d.field("grapheme_break"),
is_symbol.field("is_symbol"),
d.field("is_emoji_modifier"),
d.field("is_emoji_modifier_base"),
},
},
};

View File

@@ -41,7 +41,7 @@ pub const flatpak = options.flatpak;
pub const snap = options.snap;
pub const app_runtime: apprt.Runtime = config.app_runtime;
pub const font_backend: font.Backend = config.font_backend;
pub const renderer: rendererpkg.Impl = config.renderer;
pub const renderer: rendererpkg.Backend = config.renderer;
pub const i18n: bool = config.i18n;
/// The bundle ID for the app. This is used in many places and is currently

View File

@@ -49,7 +49,4 @@ pub const Wasm = if (!builtin.target.cpu.arch.isWasm()) struct {} else @import("
test {
@import("std").testing.refAllDecls(@This());
// Vim syntax file, not used at runtime but we want to keep it tested.
_ = @import("config/vim.zig");
}

View File

@@ -19,7 +19,6 @@ const ArenaAllocator = std.heap.ArenaAllocator;
const global_state = &@import("../global.zig").state;
const fontpkg = @import("../font/main.zig");
const inputpkg = @import("../input.zig");
const terminal = @import("../terminal/main.zig");
const internal_os = @import("../os/main.zig");
const cli = @import("../cli.zig");
@@ -39,6 +38,16 @@ const RepeatableStringMap = @import("RepeatableStringMap.zig");
pub const Path = @import("path.zig").Path;
pub const RepeatablePath = @import("path.zig").RepeatablePath;
// We do this instead of importing all of terminal/main.zig to
// limit the dependency graph. This is important because some things
// like the `ghostty-build-data` binary depend on the Config but don't
// want to include all the other stuff.
const terminal = struct {
const CursorStyle = @import("../terminal/cursor.zig").Style;
const color = @import("../terminal/color.zig");
const x11_color = @import("../terminal/x11_color.zig");
};
const log = std.log.scoped(.config);
/// Used on Unixes for some defaults.

View File

@@ -6,8 +6,11 @@
# {[path]s}
#
# The template does not set any default options, since Ghostty ships
# with sensible defaults for all options. Users should only need to set
# options that they want to change from the default.
# with sensible defaults for all options.
# Note that you should not paste the output of `ghostty +show-config
# --default` into your config: some default options actually conflict with each other
# when explicitly set in a configuration file. Instead, only set the
# options you actually need.
#
# Run `ghostty +show-config --default --docs` to view a list of
# all available config options and their default values.

View File

@@ -23,7 +23,7 @@ pub fn DoublyLinkedList(comptime T: type) type {
/// Arguments:
/// node: Pointer to a node in the list.
/// new_node: Pointer to the new node to insert.
pub fn insertAfter(list: *Self, node: *Node, new_node: *Node) void {
pub inline fn insertAfter(list: *Self, node: *Node, new_node: *Node) void {
new_node.prev = node;
if (node.next) |next_node| {
// Intermediate node.
@@ -42,7 +42,7 @@ pub fn DoublyLinkedList(comptime T: type) type {
/// Arguments:
/// node: Pointer to a node in the list.
/// new_node: Pointer to the new node to insert.
pub fn insertBefore(list: *Self, node: *Node, new_node: *Node) void {
pub inline fn insertBefore(list: *Self, node: *Node, new_node: *Node) void {
new_node.next = node;
if (node.prev) |prev_node| {
// Intermediate node.
@@ -60,7 +60,7 @@ pub fn DoublyLinkedList(comptime T: type) type {
///
/// Arguments:
/// new_node: Pointer to the new node to insert.
pub fn append(list: *Self, new_node: *Node) void {
pub inline fn append(list: *Self, new_node: *Node) void {
if (list.last) |last| {
// Insert after last.
list.insertAfter(last, new_node);
@@ -74,7 +74,7 @@ pub fn DoublyLinkedList(comptime T: type) type {
///
/// Arguments:
/// new_node: Pointer to the new node to insert.
pub fn prepend(list: *Self, new_node: *Node) void {
pub inline fn prepend(list: *Self, new_node: *Node) void {
if (list.first) |first| {
// Insert before first.
list.insertBefore(first, new_node);
@@ -91,7 +91,7 @@ pub fn DoublyLinkedList(comptime T: type) type {
///
/// Arguments:
/// node: Pointer to the node to be removed.
pub fn remove(list: *Self, node: *Node) void {
pub inline fn remove(list: *Self, node: *Node) void {
if (node.prev) |prev_node| {
// Intermediate node.
prev_node.next = node.next;
@@ -113,7 +113,7 @@ pub fn DoublyLinkedList(comptime T: type) type {
///
/// Returns:
/// A pointer to the last node in the list.
pub fn pop(list: *Self) ?*Node {
pub inline fn pop(list: *Self) ?*Node {
const last = list.last orelse return null;
list.remove(last);
return last;
@@ -123,7 +123,7 @@ pub fn DoublyLinkedList(comptime T: type) type {
///
/// Returns:
/// A pointer to the first node in the list.
pub fn popFirst(list: *Self) ?*Node {
pub inline fn popFirst(list: *Self) ?*Node {
const first = list.first orelse return null;
list.remove(first);
return first;

View File

@@ -1,3 +1,4 @@
//! Fish completions.
const std = @import("std");
const Config = @import("../config/Config.zig");
@@ -5,23 +6,23 @@ const Action = @import("../cli.zig").ghostty.Action;
/// A fish completions configuration that contains all the available commands
/// and options.
pub const completions = comptimeGenerateFishCompletions();
pub const completions = comptimeGenerateCompletions();
fn comptimeGenerateFishCompletions() []const u8 {
fn comptimeGenerateCompletions() []const u8 {
comptime {
@setEvalBranchQuota(50000);
var counter = std.io.countingWriter(std.io.null_writer);
try writeFishCompletions(&counter.writer());
try writeCompletions(&counter.writer());
var buf: [counter.bytes_written]u8 = undefined;
var stream = std.io.fixedBufferStream(&buf);
try writeFishCompletions(stream.writer());
try writeCompletions(stream.writer());
const final = buf;
return final[0..stream.getWritten().len];
}
}
fn writeFishCompletions(writer: anytype) !void {
fn writeCompletions(writer: anytype) !void {
{
try writer.writeAll("set -l commands \"");
var count: usize = 0;

View File

@@ -1,5 +1,5 @@
const std = @import("std");
const Config = @import("Config.zig");
const Config = @import("../config/Config.zig");
const Template = struct {
const header =

View File

@@ -1,5 +1,5 @@
const std = @import("std");
const Config = @import("Config.zig");
const Config = @import("../config/Config.zig");
/// This is the associated Vim file as named by the variable.
pub const syntax = comptimeGenSyntax();

View File

@@ -2,13 +2,20 @@ const std = @import("std");
const builtin = @import("builtin");
const assert = std.debug.assert;
/// Same as std.mem.copyForwards but prefers libc memmove if it is available
/// because it is generally much faster.
/// Same as std.mem.copyForwards/Backwards but prefers libc memmove if it is
/// available because it is generally much faster.
pub inline fn move(comptime T: type, dest: []T, source: []const T) void {
if (builtin.link_libc) {
_ = memmove(dest.ptr, source.ptr, source.len * @sizeOf(T));
} else {
std.mem.copyForwards(T, dest, source);
// Depending on the ordering of the copy, we need to use the
// proper call here. Unfortunately this function call is
// too generic to know this at comptime.
if (@intFromPtr(dest.ptr) <= @intFromPtr(source.ptr)) {
std.mem.copyForwards(T, dest, source);
} else {
std.mem.copyBackwards(T, dest, source);
}
}
}

View File

@@ -13,7 +13,7 @@ const CodepointResolver = @This();
const std = @import("std");
const Allocator = std.mem.Allocator;
const ziglyph = @import("ziglyph");
const uucode = @import("uucode");
const font = @import("main.zig");
const Atlas = font.Atlas;
const CodepointMap = font.CodepointMap;
@@ -150,7 +150,7 @@ pub fn getIndex(
// we'll do this multiple times if we recurse, but this is a cached function
// call higher up (GroupCache) so this should be rare.
const p_mode: Collection.PresentationMode = if (p) |v| .{ .explicit = v } else .{
.default = if (ziglyph.emoji.isEmojiPresentation(@intCast(cp)))
.default = if (uucode.get(.is_emoji_presentation, @intCast(cp)))
.emoji
else
.text,

110
src/font/backend.zig Normal file
View File

@@ -0,0 +1,110 @@
const std = @import("std");
pub const Backend = enum {
const WasmTarget = @import("../os/wasm/target.zig").Target;
/// FreeType for font rendering with no font discovery enabled.
freetype,
/// Fontconfig for font discovery and FreeType for font rendering.
fontconfig_freetype,
/// CoreText for font discovery, rendering, and shaping (macOS).
coretext,
/// CoreText for font discovery, FreeType for rendering, and
/// HarfBuzz for shaping (macOS).
coretext_freetype,
/// CoreText for font discovery and rendering, HarfBuzz for shaping
coretext_harfbuzz,
/// CoreText for font discovery and rendering, no shaping.
coretext_noshape,
/// Use the browser font system and the Canvas API (wasm). This limits
/// the available fonts to browser fonts (anything Canvas natively
/// supports).
web_canvas,
/// Returns the default backend for a build environment. This is
/// meant to be called at comptime by the build.zig script. To get the
/// backend look at build_options.
pub fn default(
target: std.Target,
wasm_target: WasmTarget,
) Backend {
if (target.cpu.arch == .wasm32) {
return switch (wasm_target) {
.browser => .web_canvas,
};
}
// macOS also supports "coretext_freetype" but there is no scenario
// that is the default. It is only used by people who want to
// self-compile Ghostty and prefer the freetype aesthetic.
return if (target.os.tag.isDarwin()) .coretext else .fontconfig_freetype;
}
// All the functions below can be called at comptime or runtime to
// determine if we have a certain dependency.
pub fn hasFreetype(self: Backend) bool {
return switch (self) {
.freetype,
.fontconfig_freetype,
.coretext_freetype,
=> true,
.coretext,
.coretext_harfbuzz,
.coretext_noshape,
.web_canvas,
=> false,
};
}
pub fn hasCoretext(self: Backend) bool {
return switch (self) {
.coretext,
.coretext_freetype,
.coretext_harfbuzz,
.coretext_noshape,
=> true,
.freetype,
.fontconfig_freetype,
.web_canvas,
=> false,
};
}
pub fn hasFontconfig(self: Backend) bool {
return switch (self) {
.fontconfig_freetype => true,
.freetype,
.coretext,
.coretext_freetype,
.coretext_harfbuzz,
.coretext_noshape,
.web_canvas,
=> false,
};
}
pub fn hasHarfbuzz(self: Backend) bool {
return switch (self) {
.freetype,
.fontconfig_freetype,
.coretext_freetype,
.coretext_harfbuzz,
=> true,
.coretext,
.coretext_noshape,
.web_canvas,
=> false,
};
}
};

View File

@@ -5,6 +5,7 @@ const build_config = @import("../build_config.zig");
const library = @import("library.zig");
pub const Atlas = @import("Atlas.zig");
pub const Backend = @import("backend.zig").Backend;
pub const discovery = @import("discovery.zig");
pub const embedded = @import("embedded.zig");
pub const face = @import("face.zig");
@@ -48,115 +49,6 @@ pub const options: struct {
.backend = if (builtin.target.cpu.arch.isWasm()) .web_canvas else build_config.font_backend,
};
pub const Backend = enum {
const WasmTarget = @import("../os/wasm/target.zig").Target;
/// FreeType for font rendering with no font discovery enabled.
freetype,
/// Fontconfig for font discovery and FreeType for font rendering.
fontconfig_freetype,
/// CoreText for font discovery, rendering, and shaping (macOS).
coretext,
/// CoreText for font discovery, FreeType for rendering, and
/// HarfBuzz for shaping (macOS).
coretext_freetype,
/// CoreText for font discovery and rendering, HarfBuzz for shaping
coretext_harfbuzz,
/// CoreText for font discovery and rendering, no shaping.
coretext_noshape,
/// Use the browser font system and the Canvas API (wasm). This limits
/// the available fonts to browser fonts (anything Canvas natively
/// supports).
web_canvas,
/// Returns the default backend for a build environment. This is
/// meant to be called at comptime by the build.zig script. To get the
/// backend look at build_options.
pub fn default(
target: std.Target,
wasm_target: WasmTarget,
) Backend {
if (target.cpu.arch == .wasm32) {
return switch (wasm_target) {
.browser => .web_canvas,
};
}
// macOS also supports "coretext_freetype" but there is no scenario
// that is the default. It is only used by people who want to
// self-compile Ghostty and prefer the freetype aesthetic.
return if (target.os.tag.isDarwin()) .coretext else .fontconfig_freetype;
}
// All the functions below can be called at comptime or runtime to
// determine if we have a certain dependency.
pub fn hasFreetype(self: Backend) bool {
return switch (self) {
.freetype,
.fontconfig_freetype,
.coretext_freetype,
=> true,
.coretext,
.coretext_harfbuzz,
.coretext_noshape,
.web_canvas,
=> false,
};
}
pub fn hasCoretext(self: Backend) bool {
return switch (self) {
.coretext,
.coretext_freetype,
.coretext_harfbuzz,
.coretext_noshape,
=> true,
.freetype,
.fontconfig_freetype,
.web_canvas,
=> false,
};
}
pub fn hasFontconfig(self: Backend) bool {
return switch (self) {
.fontconfig_freetype => true,
.freetype,
.coretext,
.coretext_freetype,
.coretext_harfbuzz,
.coretext_noshape,
.web_canvas,
=> false,
};
}
pub fn hasHarfbuzz(self: Backend) bool {
return switch (self) {
.freetype,
.fontconfig_freetype,
.coretext_freetype,
.coretext_harfbuzz,
=> true,
.coretext,
.coretext_noshape,
.web_canvas,
=> false,
};
}
};
/// The styles that a family can take.
pub const Style = enum(u3) {
regular = 0,

View File

@@ -1,9 +1,9 @@
const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const ziglyph = @import("ziglyph");
const font = @import("../main.zig");
const terminal = @import("../../terminal/main.zig");
const unicode = @import("../../unicode/main.zig");
const log = std.log.scoped(.font_shaper);
@@ -111,7 +111,7 @@ pub const Shaper = struct {
// font ligatures. However, we do support grapheme clustering.
// This means we can render things like skin tone emoji but
// we can't render things like single glyph "=>".
var break_state: u3 = 0;
var break_state: unicode.GraphemeBreakState = .{};
var cp1: u21 = @intCast(codepoints[0]);
var start: usize = 0;
@@ -126,7 +126,7 @@ pub const Shaper = struct {
const cp2: u21 = @intCast(codepoints[i]);
defer cp1 = cp2;
break :blk ziglyph.graphemeBreak(
break :blk unicode.graphemeBreak(
cp1,
cp2,
&break_state,

View File

@@ -4,7 +4,7 @@
const std = @import("std");
const Config = @import("config/Config.zig");
const Action = @import("cli.zig").ghostty.Action;
const Action = @import("cli/ghostty.zig").Action;
const KeybindAction = @import("input/Binding.zig").Action;
pub fn main() !void {

View File

@@ -6,7 +6,7 @@ const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const build_config = @import("../build_config.zig");
const ziglyph = @import("ziglyph");
const uucode = @import("uucode");
const key = @import("key.zig");
const KeyEvent = key.KeyEvent;
@@ -1618,15 +1618,19 @@ pub const Trigger = struct {
/// in more codepoints so we need to use a 3 element array.
fn foldedCodepoint(cp: u21) [3]u21 {
// ASCII fast path
if (ziglyph.letter.isAsciiLetter(cp)) {
return .{ ziglyph.letter.toLower(cp), 0, 0 };
if (uucode.ascii.isAlphabetic(cp)) {
return .{ uucode.ascii.toLower(cp), 0, 0 };
}
// Unicode slow path. Case folding can resultin more codepoints.
// Unicode slow path. Case folding can result in more codepoints.
// If more codepoints are produced then we return the codepoint
// as-is which isn't correct but until we have a failing test
// then I don't want to handle this.
return ziglyph.letter.toCaseFold(cp);
var buffer: [1]u21 = undefined;
const slice = uucode.get(.case_folding_full, cp).with(&buffer, cp);
var array: [3]u21 = [_]u21{0} ** 3;
@memcpy(array[0..slice.len], slice);
return array;
}
/// Convert the trigger to a C API compatible trigger.

View File

@@ -197,7 +197,9 @@ pub const VTEvent = struct {
) !void {
switch (@TypeOf(v)) {
void => {},
[]const u8 => try md.put("data", try alloc.dupeZ(u8, v)),
[]const u8,
[:0]const u8,
=> try md.put("data", try alloc.dupeZ(u8, v)),
else => |T| switch (@typeInfo(T)) {
.@"struct" => |info| inline for (info.fields) |field| {
try encodeMetadataSingle(
@@ -284,7 +286,9 @@ pub const VTEvent = struct {
try std.fmt.allocPrintZ(alloc, "{}", .{value}),
),
[]const u8 => try md.put(key, try alloc.dupeZ(u8, value)),
[]const u8,
[:0]const u8,
=> try md.put(key, try alloc.dupeZ(u8, value)),
else => |T| {
@compileLog(T);

255
src/lib/allocator.zig Normal file
View File

@@ -0,0 +1,255 @@
const std = @import("std");
const builtin = @import("builtin");
const testing = std.testing;
/// Useful alias since they're required to create Zig allocators
pub const ZigVTable = std.mem.Allocator.VTable;
/// The VTable required by the C interface.
/// C: GhosttyAllocatorVtable
pub const VTable = extern struct {
alloc: *const fn (*anyopaque, len: usize, alignment: u8, ret_addr: usize) callconv(.c) ?[*]u8,
resize: *const fn (*anyopaque, memory: [*]u8, memory_len: usize, alignment: u8, new_len: usize, ret_addr: usize) callconv(.c) bool,
remap: *const fn (*anyopaque, memory: [*]u8, memory_len: usize, alignment: u8, new_len: usize, ret_addr: usize) callconv(.c) ?[*]u8,
free: *const fn (*anyopaque, memory: [*]u8, memory_len: usize, alignment: u8, ret_addr: usize) callconv(.c) void,
};
/// Returns an allocator to use for the given possibly-null C allocator,
/// ensuring some allocator is always returned.
pub fn default(c_alloc_: ?*const Allocator) std.mem.Allocator {
// If we're given an allocator, use it.
if (c_alloc_) |c_alloc| return c_alloc.zig();
// If we have libc, use that. We prefer libc if we have it because
// its generally fast but also lets the embedder easily override
// malloc/free with custom allocators like mimalloc or something.
if (comptime builtin.link_libc) return std.heap.c_allocator;
// No libc, use the preferred allocator for releases which is the
// Zig SMP allocator.
return std.heap.smp_allocator;
}
/// The Allocator interface for custom memory allocation strategies
/// within C libghostty APIs.
///
/// This -- purposely -- matches the Zig allocator interface. We do this
/// for two reasons: (1) Zig's allocator interface is well proven in
/// the real world to be flexible and useful, and (2) it allows us to
/// easily convert C allocators to Zig allocators and vice versa, since
/// we're written in Zig.
///
/// C: GhosttyAllocator
pub const Allocator = extern struct {
ctx: *anyopaque,
vtable: *const VTable,
/// vtable for the Zig allocator interface to map our extern
/// allocator to Zig's allocator interface.
pub const zig_vtable: ZigVTable = .{
.alloc = alloc,
.resize = resize,
.remap = remap,
.free = free,
};
/// Create a C allocator from a Zig allocator. This requires that
/// the Zig allocator be pointer-stable for the lifetime of the
/// C allocator.
pub fn fromZig(zig_alloc: *const std.mem.Allocator) Allocator {
return .{
.ctx = @ptrCast(@constCast(zig_alloc)),
.vtable = &ZigAllocator.vtable,
};
}
/// Create a Zig allocator from this C allocator. This requires
/// a pointer to a Zig allocator vtable that we can populate with
/// our callbacks.
pub fn zig(self: *const Allocator) std.mem.Allocator {
return .{
.ptr = @ptrCast(@constCast(self)),
.vtable = &zig_vtable,
};
}
fn alloc(
ctx: *anyopaque,
len: usize,
alignment: std.mem.Alignment,
ra: usize,
) ?[*]u8 {
const self: *Allocator = @ptrCast(@alignCast(ctx));
return self.vtable.alloc(
self.ctx,
len,
@intFromEnum(alignment),
ra,
);
}
fn resize(
ctx: *anyopaque,
old_mem: []u8,
alignment: std.mem.Alignment,
new_len: usize,
ra: usize,
) bool {
const self: *Allocator = @ptrCast(@alignCast(ctx));
return self.vtable.resize(
self.ctx,
old_mem.ptr,
old_mem.len,
@intFromEnum(alignment),
new_len,
ra,
);
}
fn remap(
ctx: *anyopaque,
old_mem: []u8,
alignment: std.mem.Alignment,
new_len: usize,
ra: usize,
) ?[*]u8 {
const self: *Allocator = @ptrCast(@alignCast(ctx));
return self.vtable.remap(
self.ctx,
old_mem.ptr,
old_mem.len,
@intFromEnum(alignment),
new_len,
ra,
);
}
fn free(
ctx: *anyopaque,
old_mem: []u8,
alignment: std.mem.Alignment,
ra: usize,
) void {
const self: *Allocator = @ptrCast(@alignCast(ctx));
self.vtable.free(
self.ctx,
old_mem.ptr,
old_mem.len,
@intFromEnum(alignment),
ra,
);
}
};
/// An allocator implementation that wraps a Zig allocator so that
/// it can be exposed to C.
const ZigAllocator = struct {
const vtable: VTable = .{
.alloc = alloc,
.resize = resize,
.remap = remap,
.free = free,
};
fn alloc(
ctx: *anyopaque,
len: usize,
alignment: u8,
ra: usize,
) callconv(.c) ?[*]u8 {
const zig_alloc: *const std.mem.Allocator = @ptrCast(@alignCast(ctx));
return zig_alloc.vtable.alloc(
zig_alloc.ptr,
len,
@enumFromInt(alignment),
ra,
);
}
fn resize(
ctx: *anyopaque,
memory: [*]u8,
memory_len: usize,
alignment: u8,
new_len: usize,
ra: usize,
) callconv(.c) bool {
const zig_alloc: *const std.mem.Allocator = @ptrCast(@alignCast(ctx));
return zig_alloc.vtable.resize(
zig_alloc.ptr,
memory[0..memory_len],
@enumFromInt(alignment),
new_len,
ra,
);
}
fn remap(
ctx: *anyopaque,
memory: [*]u8,
memory_len: usize,
alignment: u8,
new_len: usize,
ra: usize,
) callconv(.c) ?[*]u8 {
const zig_alloc: *const std.mem.Allocator = @ptrCast(@alignCast(ctx));
return zig_alloc.vtable.remap(
zig_alloc.ptr,
memory[0..memory_len],
@enumFromInt(alignment),
new_len,
ra,
);
}
fn free(
ctx: *anyopaque,
memory: [*]u8,
memory_len: usize,
alignment: u8,
ra: usize,
) callconv(.c) void {
const zig_alloc: *const std.mem.Allocator = @ptrCast(@alignCast(ctx));
return zig_alloc.vtable.free(
zig_alloc.ptr,
memory[0..memory_len],
@enumFromInt(alignment),
ra,
);
}
};
/// libc Allocator, requires linking libc
pub const c_allocator: Allocator = .fromZig(&std.heap.c_allocator);
/// Allocator that can be sent to the C API that does full
/// leak checking within Zig tests. This should only be used from
/// Zig tests.
pub const test_allocator: Allocator = b: {
if (!builtin.is_test) @compileError("test_allocator can only be used in tests");
break :b .fromZig(&testing.allocator);
};
test "c allocator" {
if (!comptime builtin.link_libc) return error.SkipZigTest;
const alloc = c_allocator.zig();
const str = try alloc.alloc(u8, 10);
defer alloc.free(str);
try testing.expectEqual(10, str.len);
}
test "fba allocator" {
var buf: [1024]u8 = undefined;
var fba: std.heap.FixedBufferAllocator = .init(&buf);
const zig_alloc = fba.allocator();
// Convert the Zig allocator to a C interface
const c_alloc: Allocator = .fromZig(&zig_alloc);
// Convert back to Zig so we can test it.
const alloc = c_alloc.zig();
const str = try alloc.alloc(u8, 10);
defer alloc.free(str);
try testing.expectEqual(10, str.len);
}

97
src/lib/enum.zig Normal file
View File

@@ -0,0 +1,97 @@
const std = @import("std");
/// Create an enum type with the given keys that is C ABI compatible
/// if we're targeting C, otherwise a Zig enum with smallest possible
/// backing type.
///
/// In all cases, the enum keys will be created in the order given.
/// For C ABI, this means that the order MUST NOT be changed in order
/// to preserve ABI compatibility. You can set a key to null to
/// remove it from the Zig enum while keeping the "hole" in the C enum
/// to preserve ABI compatibility.
///
/// C detection is up to the caller, since there are multiple ways
/// to do that. We rely on the `target` parameter to determine whether we
/// should create a C compatible enum or a Zig enum.
///
/// For the Zig enum, the enum value is not guaranteed to be stable, so
/// it shouldn't be relied for things like serialization.
pub fn Enum(
target: Target,
keys: []const ?[:0]const u8,
) type {
var fields: [keys.len]std.builtin.Type.EnumField = undefined;
var fields_i: usize = 0;
var holes: usize = 0;
for (keys) |key_| {
const key: [:0]const u8 = key_ orelse {
switch (target) {
// For Zig we don't track holes because the enum value
// isn't guaranteed to be stable and we want to use the
// smallest possible backing type.
.zig => {},
// For C we must track holes to preserve ABI compatibility
// with subsequent values.
.c => holes += 1,
}
continue;
};
fields[fields_i] = .{
.name = key,
.value = fields_i + holes,
};
fields_i += 1;
}
// Assigned to var so that the type name is nicer in stack traces.
const Result = @Type(.{ .@"enum" = .{
.tag_type = switch (target) {
.c => c_int,
.zig => std.math.IntFittingRange(0, fields_i - 1),
},
.fields = fields[0..fields_i],
.decls = &.{},
.is_exhaustive = true,
} });
return Result;
}
pub const Target = union(enum) {
c,
zig,
};
test "zig" {
const testing = std.testing;
const T = Enum(.zig, &.{ "a", "b", "c", "d" });
const info = @typeInfo(T).@"enum";
try testing.expectEqual(u2, info.tag_type);
}
test "c" {
const testing = std.testing;
const T = Enum(.c, &.{ "a", "b", "c", "d" });
const info = @typeInfo(T).@"enum";
try testing.expectEqual(c_int, info.tag_type);
}
test "abi by removing a key" {
const testing = std.testing;
// C
{
const T = Enum(.c, &.{ "a", "b", null, "d" });
const info = @typeInfo(T).@"enum";
try testing.expectEqual(c_int, info.tag_type);
try testing.expectEqual(3, @intFromEnum(T.d));
}
// Zig
{
const T = Enum(.zig, &.{ "a", "b", null, "d" });
const info = @typeInfo(T).@"enum";
try testing.expectEqual(u2, info.tag_type);
try testing.expectEqual(2, @intFromEnum(T.d));
}
}

10
src/lib/main.zig Normal file
View File

@@ -0,0 +1,10 @@
const std = @import("std");
const enumpkg = @import("enum.zig");
pub const allocator = @import("allocator.zig");
pub const Enum = enumpkg.Enum;
pub const EnumTarget = enumpkg.Target;
test {
std.testing.refAllDecls(@This());
}

90
src/lib_vt.zig Normal file
View File

@@ -0,0 +1,90 @@
//! This is the public API of the ghostty-vt Zig module.
//!
//! WARNING: The API is not guaranteed to be stable.
//!
//! The functionality is extremely stable, since it is extracted
//! directly from Ghostty which has been used in real world scenarios
//! by thousands of users for years. However, the API itself (functions,
//! types, etc.) may change without warning. We're working on stabilizing
//! this in the future.
const lib = @This();
// The public API below reproduces a lot of terminal/main.zig but
// is separate because (1) we need our root file to be in `src/`
// so we can access other directories and (2) we may want to withhold
// parts of `terminal` that are not ready for public consumption
// or are too Ghostty-internal.
const terminal = @import("terminal/main.zig");
pub const apc = terminal.apc;
pub const dcs = terminal.dcs;
pub const osc = terminal.osc;
pub const point = terminal.point;
pub const color = terminal.color;
pub const device_status = terminal.device_status;
pub const kitty = terminal.kitty;
pub const modes = terminal.modes;
pub const page = terminal.page;
pub const parse_table = terminal.parse_table;
pub const search = terminal.search;
pub const size = terminal.size;
pub const x11_color = terminal.x11_color;
pub const Charset = terminal.Charset;
pub const CharsetSlot = terminal.CharsetSlot;
pub const CharsetActiveSlot = terminal.CharsetActiveSlot;
pub const Cell = page.Cell;
pub const Coordinate = point.Coordinate;
pub const CSI = Parser.Action.CSI;
pub const DCS = Parser.Action.DCS;
pub const MouseShape = terminal.MouseShape;
pub const Page = page.Page;
pub const PageList = terminal.PageList;
pub const Parser = terminal.Parser;
pub const Pin = PageList.Pin;
pub const Point = point.Point;
pub const Screen = terminal.Screen;
pub const ScreenType = Terminal.ScreenType;
pub const Selection = terminal.Selection;
pub const SizeReportStyle = terminal.SizeReportStyle;
pub const StringMap = terminal.StringMap;
pub const Style = terminal.Style;
pub const Terminal = terminal.Terminal;
pub const Stream = terminal.Stream;
pub const Cursor = Screen.Cursor;
pub const CursorStyle = Screen.CursorStyle;
pub const CursorStyleReq = terminal.CursorStyle;
pub const DeviceAttributeReq = terminal.DeviceAttributeReq;
pub const Mode = modes.Mode;
pub const ModePacked = modes.ModePacked;
pub const ModifyKeyFormat = terminal.ModifyKeyFormat;
pub const ProtectedMode = terminal.ProtectedMode;
pub const StatusLineType = terminal.StatusLineType;
pub const StatusDisplay = terminal.StatusDisplay;
pub const EraseDisplay = terminal.EraseDisplay;
pub const EraseLine = terminal.EraseLine;
pub const TabClear = terminal.TabClear;
pub const Attribute = terminal.Attribute;
comptime {
// If we're building the C library (vs. the Zig module) then
// we want to reference the C API so that it gets exported.
if (@import("root") == lib) {
const c = terminal.c_api;
@export(&c.osc_new, .{ .name = "ghostty_osc_new" });
@export(&c.osc_free, .{ .name = "ghostty_osc_free" });
@export(&c.osc_next, .{ .name = "ghostty_osc_next" });
@export(&c.osc_reset, .{ .name = "ghostty_osc_reset" });
@export(&c.osc_end, .{ .name = "ghostty_osc_end" });
@export(&c.osc_command_type, .{ .name = "ghostty_osc_command_type" });
@export(&c.osc_command_data, .{ .name = "ghostty_osc_command_data" });
}
}
test {
_ = terminal;
_ = @import("lib/main.zig");
if (comptime terminal.options.c_abi) {
_ = terminal.c_api;
}
}

Some files were not shown because too many files have changed in this diff Show More