48 Commits
tip ... 1.2.x

Author SHA1 Message Date
Mitchell Hashimoto
055281febf 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 13:03:12 -07:00
Mitchell Hashimoto
64edc95e92 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 13:03:05 -07:00
Mitchell Hashimoto
359d735213 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 13:02:54 -07:00
Mitchell Hashimoto
e10eb8a2fd 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-29 13:02:37 -07:00
Mitchell Hashimoto
8b047fb570 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-29 13:01:54 -07:00
Mitchell Hashimoto
f764c070bd cli: use sh to launch editor (#8901)
Fixes #8898
2025-09-29 13:01:48 -07:00
Mitchell Hashimoto
d06c9c7aae 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-29 13:01:43 -07:00
Mitchell Hashimoto
eb0814c680 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-29 13:01:27 -07:00
Mitchell Hashimoto
7aff259fee 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-29 13:01:16 -07:00
Mitchell Hashimoto
a2b6a9cf99 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-29 13:01:09 -07:00
Mitchell Hashimoto
4cb3aaece4 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-29 13:00:59 -07:00
Mitchell Hashimoto
7a3bbe0107 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-29 13:00:53 -07:00
Mitchell Hashimoto
5110ad053e 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 13:00:46 -07:00
Mitchell Hashimoto
2be16d2242 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-29 13:00:22 -07:00
Mitchell Hashimoto
7053f5a537 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 13:00:15 -07:00
Mitchell Hashimoto
a905e14cc4 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-29 13:00:08 -07:00
Mitchell Hashimoto
e89036f716 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-29 13:00:02 -07:00
Mitchell Hashimoto
5880fa5321 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-29 12:59:18 -07:00
Mitchell Hashimoto
38503e7c33 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-29 12:59:04 -07:00
Mitchell Hashimoto
5429d1e3e2 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-29 12:58:56 -07:00
Mitchell Hashimoto
b6c3781cdc 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-29 12:58:47 -07:00
Mitchell Hashimoto
12446d7d50 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-29 12:58:40 -07:00
Mitchell Hashimoto
d231e94535 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-29 12:58:24 -07:00
Mitchell Hashimoto
e3cdf0faae macos: implement bell-features=border on macOS 2025-09-29 12:54:22 -07:00
عبد الرحمن صباهي
a9f4d4941a slightly improve logs 2025-09-29 12:54:05 -07:00
Mitchell Hashimoto
3d0846051f macos: bell-features=title works again
This was a regression we didn't fix before 1.2.
2025-09-29 12:53:42 -07:00
Mitchell Hashimoto
6e5419c561 macos: opening filepaths should make proper file URLs
Fixes #8763
2025-09-29 12:53:05 -07:00
Mitchell Hashimoto
1041a4cc9b 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-29 12:52:49 -07:00
Mitchell Hashimoto
a09b39fb57 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-29 12:52:40 -07:00
Mitchell Hashimoto
093a72da05 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-29 12:52:28 -07:00
Matthias von Arx
e0905ac794 documentation: fix MacOSDockDropBehavior valid values 2025-09-29 12:52:03 -07:00
Mitchell Hashimoto
b34f3f7208 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-29 12:51:48 -07:00
Mitchell Hashimoto
51292a9793 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-29 12:51:33 -07:00
Mitchell Hashimoto
1cd0fb5dab 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:50:49 -07:00
Daniel Wennberg
5c6a766ff6 Measure ascii height and use to upper bound ic_width 2025-09-29 12:50:01 -07:00
Leah Amelia Chen
6b1fd76b7d Default config template be explicit that you do not copy the default values (#8701) 2025-09-29 12:49:35 -07:00
Mitchell Hashimoto
581846992d 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-29 12:49:22 -07:00
Mitchell Hashimoto
86e5ec8ba5 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-29 12:49:00 -07:00
Mitchell Hashimoto
5a0bd8d1fa 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-29 12:48:45 -07:00
Filip Milković
28cdbe4f22 i18n: add Croatian hr_HR translation (#8668) 2025-09-29 12:48:34 -07:00
Simon Olofsson
a4126d025b config: update theme names in docs
They were renamed, see: https://github.com/mbadolato/iTerm2-Color-Schemes/commits/master/ghostty/Rose%20Pine
2025-09-29 12:48:06 -07:00
カワリミ人形
b4345d151a docs: add lacking version information
`quick-terminal-size` option is available since 1.2.0
2025-09-29 12:47:56 -07:00
rhodes-b
af77332871 mark ssh shell-integration wrapper as a function this matches other features + fixes a case where users alias to some other command 2025-09-29 12:47:27 -07:00
dmunozv04
c33ea2757c Docs: add undo-timeout configuration setting name 2025-09-29 12:47:16 -07:00
Caleb Hearth
6753507826 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-29 12:47:05 -07:00
Nilton Perim Neto
7884909253 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-29 12:46:45 -07:00
Daniel Wennberg
812dc7cf2f Rewrite constraint code for improved icon scaling/alignment 2025-09-29 12:45:56 -07:00
Peter Dave Hello
81027f2211 Add zh_TW Traditional Chinese locale 2025-09-29 12:45:21 -07:00
173 changed files with 7091 additions and 4660 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

22
build.zig.zon.json generated
View File

@@ -24,10 +24,10 @@
"url": "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz", "url": "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz",
"hash": "sha256-FKLtu1Ccs+UamlPj9eQ12/WXFgS0uDPmPmB26MCpl7U=" "hash": "sha256-FKLtu1Ccs+UamlPj9eQ12/WXFgS0uDPmPmB26MCpl7U="
}, },
"gobject-0.3.0-Skun7ET3nQCqJhDL0KnF_X7M4L7o7JePsJBbrYpEr7UV": { "gobject-0.3.0-Skun7ET3nQAc0LzvO0NAvTiGGnmkF36cnmbeCAF6MB7Z": {
"name": "gobject", "name": "gobject",
"url": "https://github.com/ghostty-org/zig-gobject/releases/download/2025-09-20-20-1/ghostty-gobject-2025-09-20-20-1.tar.zst", "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-SXiqGm81aUn6yq1wFXgNTAULdKOHS/Rzkp5OgNkkcXo=" "hash": "sha256-h6aKUerGlX2ATVEeoN03eWaqDqvUmKdedgpxrSoHvrY="
}, },
"N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr": { "N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr": {
"name": "gtk4_layer_shell", "name": "gtk4_layer_shell",
@@ -49,10 +49,10 @@
"url": "https://deps.files.ghostty.org/imgui-1220bc6b9daceaf7c8c60f3c3998058045ba0c5c5f48ae255ff97776d9cd8bfc6402.tar.gz", "url": "https://deps.files.ghostty.org/imgui-1220bc6b9daceaf7c8c60f3c3998058045ba0c5c5f48ae255ff97776d9cd8bfc6402.tar.gz",
"hash": "sha256-oF/QHgTPEat4Hig4fGIdLkIPHmBEyOJ6JeYD6pnveGA=" "hash": "sha256-oF/QHgTPEat4Hig4fGIdLkIPHmBEyOJ6JeYD6pnveGA="
}, },
"N-V-__8AACEnAwCkyrJ_XqdomYlR8bpuh0l8WDidEz-BAzIv": { "N-V-__8AANodAwDnyHwhlOv5cVRn2rx_dTvija-wy5YtTw1B": {
"name": "iterm2_themes", "name": "iterm2_themes",
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20250922-150534-d28055b/ghostty-themes.tgz", "url": "https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz",
"hash": "sha256-mdhUxAAqKxRRXwED2laabUo9ZZqZa/MZAsO0+Y9L7uQ=" "hash": "sha256-6rKNFpaUvSbvNZ0/+u0h4I/RRaV5V7xIPQ9y7eNVbCA="
}, },
"N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x": { "N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x": {
"name": "jetbrains_mono", "name": "jetbrains_mono",
@@ -109,11 +109,6 @@
"url": "https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz", "url": "https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz",
"hash": "sha256-/8ZooxDndgfTk/PBizJxXyI9oerExNbgV5oR345rWc8=" "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": { "vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn": {
"name": "vaxis", "name": "vaxis",
"url": "git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23", "url": "git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23",
@@ -169,6 +164,11 @@
"url": "git+https://github.com/TUSF/zigimg#31268548fe3276c0e95f318a6c0d2ab10565b58d", "url": "git+https://github.com/TUSF/zigimg#31268548fe3276c0e95f318a6c0d2ab10565b58d",
"hash": "sha256-oblfr2FIzuqq0FLo/RrzCwUX1NJJuT53EwD3nP3KwN0=" "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": { "N-V-__8AAB0eQwD-0MdOEBmz7intriBReIsIDNlukNVoNu6o": {
"name": "zlib", "name": "zlib",
"url": "https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz", "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-Skun7ET3nQCqJhDL0KnF_X7M4L7o7JePsJBbrYpEr7UV"; name = "gobject-0.3.0-Skun7ET3nQAc0LzvO0NAvTiGGnmkF36cnmbeCAF6MB7Z";
path = fetchZigArtifact { path = fetchZigArtifact {
name = "gobject"; name = "gobject";
url = "https://github.com/ghostty-org/zig-gobject/releases/download/2025-09-20-20-1/ghostty-gobject-2025-09-20-20-1.tar.zst"; 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-SXiqGm81aUn6yq1wFXgNTAULdKOHS/Rzkp5OgNkkcXo="; hash = "sha256-h6aKUerGlX2ATVEeoN03eWaqDqvUmKdedgpxrSoHvrY=";
}; };
} }
{ {
@@ -163,11 +163,11 @@ in
}; };
} }
{ {
name = "N-V-__8AACEnAwCkyrJ_XqdomYlR8bpuh0l8WDidEz-BAzIv"; name = "N-V-__8AANodAwDnyHwhlOv5cVRn2rx_dTvija-wy5YtTw1B";
path = fetchZigArtifact { path = fetchZigArtifact {
name = "iterm2_themes"; name = "iterm2_themes";
url = "https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20250922-150534-d28055b/ghostty-themes.tgz"; url = "https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz";
hash = "sha256-mdhUxAAqKxRRXwED2laabUo9ZZqZa/MZAsO0+Y9L7uQ="; hash = "sha256-6rKNFpaUvSbvNZ0/+u0h4I/RRaV5V7xIPQ9y7eNVbCA=";
}; };
} }
{ {
@@ -258,14 +258,6 @@ in
hash = "sha256-/8ZooxDndgfTk/PBizJxXyI9oerExNbgV5oR345rWc8="; 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"; name = "vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn";
path = fetchZigArtifact { path = fetchZigArtifact {
@@ -354,6 +346,14 @@ in
hash = "sha256-oblfr2FIzuqq0FLo/RrzCwUX1NJJuT53EwD3nP3KwN0="; 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"; name = "N-V-__8AAB0eQwD-0MdOEBmz7intriBReIsIDNlukNVoNu6o";
path = fetchZigArtifact { path = fetchZigArtifact {

6
build.zig.zon.txt generated
View File

@@ -8,6 +8,7 @@ https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918
https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz https://deps.files.ghostty.org/fontconfig-2.14.2.tar.gz
https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz https://deps.files.ghostty.org/freetype-1220b81f6ecfb3fd222f76cf9106fecfa6554ab07ec7fdc4124b9bb063ae2adf969d.tar.gz
https://deps.files.ghostty.org/gettext-0.24.tar.gz https://deps.files.ghostty.org/gettext-0.24.tar.gz
https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz
https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz 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/gtk4-layer-shell-1.1.0.tar.gz
https://deps.files.ghostty.org/harfbuzz-11.0.0.tar.xz https://deps.files.ghostty.org/harfbuzz-11.0.0.tar.xz
@@ -25,10 +26,9 @@ https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.
https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz
https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.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/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz
https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
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/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/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/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz
https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz
https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz

189
example/app.ts Normal file
View File

@@ -0,0 +1,189 @@
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);
});

View File

@@ -1,17 +0,0 @@
# 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
```

View File

@@ -1,42 +0,0 @@
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

@@ -1,24 +0,0 @@
.{
.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",
},
}

View File

@@ -1,36 +0,0 @@
#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;
}

15
example/index.html Normal file
View File

@@ -0,0 +1,15 @@
<!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 Normal file

File diff suppressed because it is too large Load Diff

22
example/package.json Normal file
View File

@@ -0,0 +1,22 @@
{
"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"
}
}

View File

@@ -1,14 +0,0 @@
# 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
```

View File

@@ -1,50 +0,0 @@
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

@@ -1,24 +0,0 @@
.{
.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

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

View File

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

View File

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

View File

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

View File

@@ -30,6 +30,19 @@ modules:
contents: INPUT(libbz2.so) contents: INPUT(libbz2.so)
dest-filename: libbzip2.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 - name: gtk4-layer-shell
buildsystem: meson buildsystem: meson
sources: sources:

View File

@@ -31,9 +31,9 @@
}, },
{ {
"type": "archive", "type": "archive",
"url": "https://github.com/ghostty-org/zig-gobject/releases/download/2025-09-20-20-1/ghostty-gobject-2025-09-20-20-1.tar.zst", "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-Skun7ET3nQCqJhDL0KnF_X7M4L7o7JePsJBbrYpEr7UV", "dest": "vendor/p/gobject-0.3.0-Skun7ET3nQAc0LzvO0NAvTiGGnmkF36cnmbeCAF6MB7Z",
"sha256": "4978aa1a6f356949facaad7015780d4c050b74a3874bf473929e4e80d924717a" "sha256": "87a68a51eac6957d804d511ea0dd377966aa0eabd498a75e760a71ad2a07beb6"
}, },
{ {
"type": "archive", "type": "archive",
@@ -61,9 +61,9 @@
}, },
{ {
"type": "archive", "type": "archive",
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20250922-150534-d28055b/ghostty-themes.tgz", "url": "https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz",
"dest": "vendor/p/N-V-__8AACEnAwCkyrJ_XqdomYlR8bpuh0l8WDidEz-BAzIv", "dest": "vendor/p/N-V-__8AANodAwDnyHwhlOv5cVRn2rx_dTvija-wy5YtTw1B",
"sha256": "99d854c4002a2b14515f0103da569a6d4a3d659a996bf31902c3b4f98f4beee4" "sha256": "eab28d169694bd26ef359d3ffaed21e08fd145a57957bc483d0f72ede3556c20"
}, },
{ {
"type": "archive", "type": "archive",
@@ -131,12 +131,6 @@
"dest": "vendor/p/N-V-__8AAHffAgDU0YQmynL8K35WzkcnMUmBVQHQ0jlcKpjH", "dest": "vendor/p/N-V-__8AAHffAgDU0YQmynL8K35WzkcnMUmBVQHQ0jlcKpjH",
"sha256": "ffc668a310e77607d393f3c18b32715f223da1eac4c4d6e0579a11df8e6b59cf" "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", "type": "git",
"url": "https://github.com/rockorager/libvaxis", "url": "https://github.com/rockorager/libvaxis",
@@ -203,6 +197,12 @@
"commit": "31268548fe3276c0e95f318a6c0d2ab10565b58d", "commit": "31268548fe3276c0e95f318a6c0d2ab10565b58d",
"dest": "vendor/p/zigimg-0.1.0-lly-O6N2EABOxke8dqyzCwhtUCAafqP35zC7wsZ4Ddxj" "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", "type": "archive",
"url": "https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz", "url": "https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz",

View File

@@ -1,455 +0,0 @@
/**
* @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,19 +10,147 @@
29C15B1D2CDC3B2900520DD4 /* bat in Resources */ = {isa = PBXBuildFile; fileRef = 29C15B1C2CDC3B2000520DD4 /* bat */; }; 29C15B1D2CDC3B2900520DD4 /* bat in Resources */ = {isa = PBXBuildFile; fileRef = 29C15B1C2CDC3B2000520DD4 /* bat */; };
55154BE02B33911F001622DC /* ghostty in Resources */ = {isa = PBXBuildFile; fileRef = 55154BDF2B33911F001622DC /* ghostty */; }; 55154BE02B33911F001622DC /* ghostty in Resources */ = {isa = PBXBuildFile; fileRef = 55154BDF2B33911F001622DC /* ghostty */; };
552964E62B34A9B400030505 /* vim in Resources */ = {isa = PBXBuildFile; fileRef = 552964E52B34A9B400030505 /* vim */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; A553F4132E06EB1600257779 /* Ghostty.icon in Resources */ = {isa = PBXBuildFile; fileRef = A553F4122E06EB1600257779 /* Ghostty.icon */; };
A553F4142E06EB1600257779 /* 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 */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; FC5218FA2D10FFCE004C93E0 /* zsh in Resources */ = {isa = PBXBuildFile; fileRef = FC5218F92D10FFC7004C93E0 /* zsh */; };
FC9ABA9C2D0F53F80020D4C8 /* bash-completion in Resources */ = {isa = PBXBuildFile; fileRef = FC9ABA9B2D0F538D0020D4C8 /* bash-completion */; }; FC9ABA9C2D0F53F80020D4C8 /* bash-completion in Resources */ = {isa = PBXBuildFile; fileRef = FC9ABA9B2D0F538D0020D4C8 /* bash-completion */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@@ -42,145 +170,144 @@
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = GhosttyReleaseLocal.entitlements; sourceTree = "<group>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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>"; }; 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>"; }; FC9ABA9B2D0F538D0020D4C8 /* bash-completion */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "bash-completion"; path = "../zig-out/share/bash-completion"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* 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 */ /* 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>"; }; A54F45F42E1F047A0046BD5C /* Tests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = Tests; sourceTree = "<group>"; };
/* End PBXFileSystemSynchronizedRootGroup section */ /* End PBXFileSystemSynchronizedRootGroup section */
@@ -213,6 +340,257 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup 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 */ = { A5A1F8862A489D7400D1E8BC /* Resources */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -239,7 +617,7 @@
A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */, A5B3053D299BEAAB0047F10C /* Ghostty.entitlements */,
A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */, A51BFC282B30F26D00E92F16 /* GhosttyDebug.entitlements */,
3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */, 3B39CAA42B33949B00DABEB8 /* GhosttyReleaseLocal.entitlements */,
81F82BC72E82815D001EDFA7 /* Sources */, A54CD6ED299BEB14008C95BB /* Sources */,
A54F45F42E1F047A0046BD5C /* Tests */, A54F45F42E1F047A0046BD5C /* Tests */,
A5D495A3299BECBA00DD1313 /* Frameworks */, A5D495A3299BECBA00DD1313 /* Frameworks */,
A5A1F8862A489D7400D1E8BC /* Resources */, A5A1F8862A489D7400D1E8BC /* Resources */,
@@ -257,6 +635,28 @@
name = Products; name = Products;
sourceTree = "<group>"; 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 */ = { A5D495A3299BECBA00DD1313 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -266,6 +666,42 @@
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; 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 */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@@ -304,9 +740,6 @@
); );
dependencies = ( dependencies = (
); );
fileSystemSynchronizedGroups = (
81F82BC72E82815D001EDFA7 /* Sources */,
);
name = Ghostty; name = Ghostty;
packageProductDependencies = ( packageProductDependencies = (
A51BFC262B30F1B800E92F16 /* Sparkle */, A51BFC262B30F1B800E92F16 /* Sparkle */,
@@ -327,9 +760,6 @@
); );
dependencies = ( dependencies = (
); );
fileSystemSynchronizedGroups = (
81F82BC72E82815D001EDFA7 /* Sources */,
);
name = "Ghostty-iOS"; name = "Ghostty-iOS";
productName = "Ghostty-iOS"; productName = "Ghostty-iOS";
productReference = A5D4499D2B53AE7B000F5B83 /* Ghostty-iOS.app */; productReference = A5D4499D2B53AE7B000F5B83 /* Ghostty-iOS.app */;
@@ -395,9 +825,11 @@
files = ( files = (
FC9ABA9C2D0F53F80020D4C8 /* bash-completion in Resources */, FC9ABA9C2D0F53F80020D4C8 /* bash-completion in Resources */,
A553F4142E06EB1600257779 /* Ghostty.icon in Resources */, A553F4142E06EB1600257779 /* Ghostty.icon in Resources */,
A5593FE52DF8DE3000B47B10 /* TerminalTabsTitlebarVentura.xib in Resources */,
29C15B1D2CDC3B2900520DD4 /* bat in Resources */, 29C15B1D2CDC3B2900520DD4 /* bat in Resources */,
A586167C2B7703CC009BDB1D /* fish in Resources */, A586167C2B7703CC009BDB1D /* fish in Resources */,
55154BE02B33911F001622DC /* ghostty in Resources */, 55154BE02B33911F001622DC /* ghostty in Resources */,
A5593FE32DF8D78600B47B10 /* TerminalHiddenTitlebar.xib in Resources */,
A546F1142D7B68D7003B11A0 /* locale in Resources */, A546F1142D7B68D7003B11A0 /* locale in Resources */,
A5985CE62C33060F00C57AD3 /* man in Resources */, A5985CE62C33060F00C57AD3 /* man in Resources */,
9351BE8E3D22937F003B3499 /* nvim in Resources */, 9351BE8E3D22937F003B3499 /* nvim in Resources */,
@@ -405,6 +837,14 @@
552964E62B34A9B400030505 /* vim in Resources */, 552964E62B34A9B400030505 /* vim in Resources */,
FC5218FA2D10FFCE004C93E0 /* zsh in Resources */, FC5218FA2D10FFCE004C93E0 /* zsh in Resources */,
A5B30539299BEAAB0047F10C /* Assets.xcassets 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; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -431,6 +871,113 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( 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; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -438,6 +985,20 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( 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; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@@ -1,35 +0,0 @@
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,22 +247,6 @@ class QuickTerminalController: BaseTerminalController {
// MARK: Base Controller Overrides // 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>) { override func surfaceTreeDidChange(from: SplitTree<Ghostty.SurfaceView>, to: SplitTree<Ghostty.SurfaceView>) {
super.surfaceTreeDidChange(from: from, to: to) super.surfaceTreeDidChange(from: from, to: to)

View File

@@ -233,21 +233,6 @@ class BaseTerminalController: NSWindowController,
return newView 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. /// Called when the surfaceTree variable changed.
/// ///
/// Subclasses should call super first. /// Subclasses should call super first.

View File

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

View File

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

View File

@@ -40,7 +40,7 @@
in in
stdenv.mkDerivation (finalAttrs: { stdenv.mkDerivation (finalAttrs: {
pname = "ghostty"; pname = "ghostty";
version = "1.2.1"; version = "1.2.0";
# We limit source like this to try and reduce the amount of rebuilds as possible # 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 # 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, .optimize = optimize,
}); });
const imgui_ = b.lazyDependency("imgui", .{}); const imgui = b.dependency("imgui", .{});
const lib = b.addLibrary(.{ const lib = b.addLibrary(.{
.name = "cimgui", .name = "cimgui",
.root_module = b.createModule(.{ .root_module = b.createModule(.{
@@ -52,7 +52,7 @@ pub fn build(b: *std.Build) !void {
} }
} }
if (imgui_) |imgui| lib.addIncludePath(imgui.path("")); lib.addIncludePath(imgui.path(""));
module.addIncludePath(b.path("vendor")); module.addIncludePath(b.path("vendor"));
var flags = std.ArrayList([]const u8).init(b.allocator); var flags = std.ArrayList([]const u8).init(b.allocator);
@@ -72,7 +72,6 @@ pub fn build(b: *std.Build) !void {
}); });
} }
if (imgui_) |imgui| {
lib.addCSourceFile(.{ .file = b.path("vendor/cimgui.cpp"), .flags = flags.items }); 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.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_draw.cpp"), .flags = flags.items }); lib.addCSourceFile(.{ .file = imgui.path("imgui_draw.cpp"), .flags = flags.items });
@@ -80,6 +79,7 @@ pub fn build(b: *std.Build) !void {
lib.addCSourceFile(.{ .file = imgui.path("imgui_widgets.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("imgui_tables.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("misc/freetype/imgui_freetype.cpp"), .flags = flags.items }); lib.addCSourceFile(.{ .file = imgui.path("misc/freetype/imgui_freetype.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ lib.addCSourceFile(.{
.file = imgui.path("backends/imgui_impl_opengl3.cpp"), .file = imgui.path("backends/imgui_impl_opengl3.cpp"),
.flags = flags.items, .flags = flags.items,
@@ -100,7 +100,6 @@ pub fn build(b: *std.Build) !void {
}); });
} }
} }
}
lib.installHeadersDirectory( lib.installHeadersDirectory(
b.path("vendor"), b.path("vendor"),

View File

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

View File

@@ -10,11 +10,11 @@ pub fn build(b: *std.Build) !void {
.optimize = optimize, .optimize = optimize,
}); });
const upstream = b.lazyDependency("glslang", .{}); const upstream = b.dependency("glslang", .{});
const lib = try buildGlslang(b, upstream, target, optimize); const lib = try buildGlslang(b, upstream, target, optimize);
b.installArtifact(lib); b.installArtifact(lib);
if (upstream) |v| module.addIncludePath(v.path("")); module.addIncludePath(upstream.path(""));
module.addIncludePath(b.path("override")); module.addIncludePath(b.path("override"));
if (target.query.isNative()) { if (target.query.isNative()) {
@@ -38,7 +38,7 @@ pub fn build(b: *std.Build) !void {
fn buildGlslang( fn buildGlslang(
b: *std.Build, b: *std.Build,
upstream_: ?*std.Build.Dependency, upstream: *std.Build.Dependency,
target: std.Build.ResolvedTarget, target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode, optimize: std.builtin.OptimizeMode,
) !*std.Build.Step.Compile { ) !*std.Build.Step.Compile {
@@ -52,7 +52,7 @@ fn buildGlslang(
}); });
lib.linkLibC(); lib.linkLibC();
lib.linkLibCpp(); lib.linkLibCpp();
if (upstream_) |upstream| lib.addIncludePath(upstream.path("")); lib.addIncludePath(upstream.path(""));
lib.addIncludePath(b.path("override")); lib.addIncludePath(b.path("override"));
if (target.result.os.tag.isDarwin()) { if (target.result.os.tag.isDarwin()) {
const apple_sdk = @import("apple_sdk"); const apple_sdk = @import("apple_sdk");
@@ -66,7 +66,6 @@ fn buildGlslang(
"-fno-sanitize-trap=undefined", "-fno-sanitize-trap=undefined",
}); });
if (upstream_) |upstream| {
lib.addCSourceFiles(.{ lib.addCSourceFiles(.{
.root = upstream.path(""), .root = upstream.path(""),
.flags = flags.items, .flags = flags.items,
@@ -148,7 +147,6 @@ fn buildGlslang(
"", "",
.{ .include_extensions = &.{".h"} }, .{ .include_extensions = &.{".h"} },
); );
}
return lib; return lib;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,19 +4,16 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{}); const optimize = b.standardOptimizeOption(.{});
const module = b.addModule("spirv_cross", .{ .root_source_file = b.path("main.zig"), .target = target, .optimize = optimize }); const upstream = b.dependency("spirv_cross", .{});
// For dynamic linking, we prefer dynamic linking and to search by const module = b.addModule("spirv_cross", .{ .root_source_file = b.path("main.zig") });
// mode first. Mode first will search all paths for a dynamic library module.addIncludePath(upstream.path(""));
// before falling back to static.
const dynamic_link_opts: std.Build.Module.LinkSystemLibraryOptions = .{ const lib = try buildSpirvCross(b, upstream, target, optimize);
.preferred_link_mode = .dynamic, b.installArtifact(lib);
.search_strategy = .mode_first,
};
var test_exe: ?*std.Build.Step.Compile = null;
if (target.query.isNative()) { if (target.query.isNative()) {
test_exe = b.addTest(.{ const test_exe = b.addTest(.{
.name = "test", .name = "test",
.root_module = b.createModule(.{ .root_module = b.createModule(.{
.root_source_file = b.path("main.zig"), .root_source_file = b.path("main.zig"),
@@ -24,28 +21,19 @@ pub fn build(b: *std.Build) !void {
.optimize = optimize, .optimize = optimize,
}), }),
}); });
const tests_run = b.addRunArtifact(test_exe.?); test_exe.linkLibrary(lib);
const tests_run = b.addRunArtifact(test_exe);
const test_step = b.step("test", "Run tests"); const test_step = b.step("test", "Run tests");
test_step.dependOn(&tests_run.step); test_step.dependOn(&tests_run.step);
// Uncomment this if we're debugging tests // 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( fn buildSpirvCross(
b: *std.Build, b: *std.Build,
module: *std.Build.Module, upstream: *std.Build.Dependency,
target: std.Build.ResolvedTarget, target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode, optimize: std.builtin.OptimizeMode,
) !*std.Build.Step.Compile { ) !*std.Build.Step.Compile {
@@ -74,9 +62,6 @@ fn buildSpirvCross(
"-fno-sanitize-trap=undefined", "-fno-sanitize-trap=undefined",
}); });
if (b.lazyDependency("spirv_cross", .{})) |upstream| {
lib.addIncludePath(upstream.path(""));
module.addIncludePath(upstream.path(""));
lib.addCSourceFiles(.{ lib.addCSourceFiles(.{
.root = upstream.path(""), .root = upstream.path(""),
.flags = flags.items, .flags = flags.items,
@@ -103,7 +88,6 @@ fn buildSpirvCross(
"", "",
.{ .include_extensions = &.{".h"} }, .{ .include_extensions = &.{".h"} },
); );
}
return lib; return lib;
} }

View File

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

40
pkg/utf8proc/build.zig Normal file
View File

@@ -0,0 +1,40 @@
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

@@ -0,0 +1,11 @@
.{
.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",
},
},
}

3
pkg/utf8proc/c.zig Normal file
View File

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

20
pkg/utf8proc/main.zig Normal file
View File

@@ -0,0 +1,20 @@
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,11 +131,12 @@ which should be filled in accordingly. You can then add your translations
within the newly created translation file. within the newly created translation file.
Afterwards, you need to update the list of known locales within Ghostty's Afterwards, you need to update the list of known locales within Ghostty's
build system. To do so, open `src/os/i18n_locales.zig` and find the list build system. To do so, open `src/os/i18n.zig` and find the list
of locales after the comments, then add the full locale name into the list. of locales under the `locales` variable, then add the full locale name
into the list.
The order matters, so make sure to place your locale in the correct position. The order matters, so make sure to place your locale in the correct position.
Read the comments present in the file for more details on the order. If you're Read the comment above the variable for more details on the order. If you're
unsure, place it at the end of the list. unsure, place it at the end of the list.
```zig ```zig
@@ -145,7 +146,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 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 your locale to the `CODEOWNERS` file. Find the `# Localization` section near the

View File

@@ -404,6 +404,91 @@ pub fn getData(self: Command, comptime DT: type) ?*DT {
return if (self.data) |ptr| @ptrCast(@alignCast(ptr)) else null; 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 // Copied from Zig. This is a publicly exported function but there is no
// way to get it from the std package. // way to get it from the std package.
fn createNullDelimitedEnvMap(arena: mem.Allocator, env_map: *const EnvMap) ![:null]?[*:0]u8 { fn createNullDelimitedEnvMap(arena: mem.Allocator, env_map: *const EnvMap) ![:null]?[*:0]u8 {

View File

@@ -23,7 +23,6 @@ pub const embedded = @import("apprt/embedded.zig");
pub const surface = @import("apprt/surface.zig"); pub const surface = @import("apprt/surface.zig");
pub const Action = action.Action; pub const Action = action.Action;
pub const Runtime = @import("apprt/runtime.zig").Runtime;
pub const Target = action.Target; pub const Target = action.Target;
pub const ContentScale = structs.ContentScale; pub const ContentScale = structs.ContentScale;
@@ -52,6 +51,30 @@ pub const runtime = switch (build_config.artifact) {
pub const App = runtime.App; pub const App = runtime.App;
pub const Surface = runtime.Surface; 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 { test {
_ = Runtime; _ = Runtime;
_ = runtime; _ = runtime;

View File

@@ -42,70 +42,6 @@ const GlobalShortcuts = @import("global_shortcuts.zig").GlobalShortcuts;
const log = std.log.scoped(.gtk_ghostty_application); 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. /// The primary entrypoint for the Ghostty GTK application.
/// ///
/// This requires a `ghostty.App` and `ghostty.Config` and takes /// This requires a `ghostty.App` and `ghostty.Config` and takes
@@ -241,10 +177,6 @@ pub const Application = extern struct {
) Allocator.Error!*Self { ) Allocator.Error!*Self {
const alloc = core_app.alloc; 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 // Log our GTK versions
gtk_version.logVersion(); gtk_version.logVersion();
adw_version.logVersion(); adw_version.logVersion();

View File

@@ -51,13 +51,6 @@ pub const Surface = extern struct {
pub const Tree = datastruct.SplitTree(Self); pub const Tree = datastruct.SplitTree(Self);
pub const properties = struct { 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 @"bell-ringing" = struct {
pub const name = "bell-ringing"; pub const name = "bell-ringing";
const impl = gobject.ext.defineProperty( const impl = gobject.ext.defineProperty(
@@ -303,19 +296,6 @@ pub const Surface = extern struct {
}; };
pub const signals = 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 /// Emitted whenever the surface would like to be closed for any
/// reason. /// reason.
/// ///
@@ -1694,16 +1674,6 @@ pub const Surface = extern struct {
} }
pub fn setBellRinging(self: *Self, ringing: bool) void { 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(); const priv = self.private();
if (priv.bell_ringing == ringing) return; if (priv.bell_ringing == ringing) return;
priv.bell_ringing = ringing; priv.bell_ringing = ringing;
@@ -1888,26 +1858,20 @@ pub const Surface = extern struct {
self.as(gtk.Widget).setCursorFromName(name.ptr); self.as(gtk.Widget).setCursorFromName(name.ptr);
} }
/// Handle bell features that need to happen every time a BEL is received fn propBellRinging(
/// Currently this is audio and system but this could change in the future. self: *Self,
fn ringBell(self: *Self) void { _: *gobject.ParamSpec,
_: ?*anyopaque,
) callconv(.c) void {
const priv = self.private(); const priv = self.private();
if (!priv.bell_ringing) return;
// Emit the signal
signals.bell.impl.emit(
self,
null,
.{},
null,
);
// Activate actions if they exist // Activate actions if they exist
_ = self.as(gtk.Widget).activateAction("tab.ring-bell", null); _ = self.as(gtk.Widget).activateAction("tab.ring-bell", null);
_ = self.as(gtk.Widget).activateAction("win.ring-bell", null); _ = self.as(gtk.Widget).activateAction("win.ring-bell", null);
const config = if (priv.config) |c| c.get() else return;
// Do our sound // Do our sound
const config = if (priv.config) |c| c.get() else return;
if (config.@"bell-features".audio) audio: { if (config.@"bell-features".audio) audio: {
const config_path = config.@"bell-audio-path" orelse break :audio; const config_path = config.@"bell-audio-path" orelse break :audio;
const path, const required = switch (config_path) { const path, const required = switch (config_path) {
@@ -2895,6 +2859,7 @@ pub const Surface = extern struct {
class.bindTemplateCallback("notify_mouse_hover_url", &propMouseHoverUrl); class.bindTemplateCallback("notify_mouse_hover_url", &propMouseHoverUrl);
class.bindTemplateCallback("notify_mouse_hidden", &propMouseHidden); class.bindTemplateCallback("notify_mouse_hidden", &propMouseHidden);
class.bindTemplateCallback("notify_mouse_shape", &propMouseShape); class.bindTemplateCallback("notify_mouse_shape", &propMouseShape);
class.bindTemplateCallback("notify_bell_ringing", &propBellRinging);
class.bindTemplateCallback("should_border_be_shown", &closureShouldBorderBeShown); class.bindTemplateCallback("should_border_be_shown", &closureShouldBorderBeShown);
class.bindTemplateCallback("should_unfocused_split_be_shown", &closureShouldUnfocusedSplitBeShown); class.bindTemplateCallback("should_unfocused_split_be_shown", &closureShouldUnfocusedSplitBeShown);
@@ -2919,7 +2884,6 @@ pub const Surface = extern struct {
}); });
// Signals // Signals
signals.bell.impl.register(.{});
signals.@"close-request".impl.register(.{}); signals.@"close-request".impl.register(.{});
signals.@"clipboard-read".impl.register(.{}); signals.@"clipboard-read".impl.register(.{});
signals.@"clipboard-write".impl.register(.{}); signals.@"clipboard-write".impl.register(.{});

View File

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

View File

@@ -1,29 +0,0 @@
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,7 +10,6 @@ const assert = std.debug.assert;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Benchmark = @import("Benchmark.zig"); const Benchmark = @import("Benchmark.zig");
const options = @import("options.zig"); const options = @import("options.zig");
const uucode = @import("uucode");
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig"); const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
const simd = @import("../simd/main.zig"); const simd = @import("../simd/main.zig");
const table = @import("../unicode/main.zig").table; const table = @import("../unicode/main.zig").table;
@@ -48,9 +47,6 @@ pub const Mode = enum {
/// Test our lookup table implementation. /// Test our lookup table implementation.
table, table,
/// Using uucode, with custom `width` extension based on `wcwidth`.
uucode,
}; };
/// Create a new terminal stream handler for the given arguments. /// Create a new terminal stream handler for the given arguments.
@@ -75,7 +71,6 @@ pub fn benchmark(self: *CodepointWidth) Benchmark {
.wcwidth => stepWcwidth, .wcwidth => stepWcwidth,
.table => stepTable, .table => stepTable,
.simd => stepSimd, .simd => stepSimd,
.uucode => stepUucode,
}, },
.setupFn = setup, .setupFn = setup,
.teardownFn = teardown, .teardownFn = teardown,
@@ -185,35 +180,6 @@ 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 { test CodepointWidth {
const testing = std.testing; const testing = std.testing;
const alloc = testing.allocator; const alloc = testing.allocator;

View File

@@ -8,7 +8,6 @@ const assert = std.debug.assert;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const Benchmark = @import("Benchmark.zig"); const Benchmark = @import("Benchmark.zig");
const options = @import("options.zig"); const options = @import("options.zig");
const uucode = @import("uucode");
const UTF8Decoder = @import("../terminal/UTF8Decoder.zig"); const UTF8Decoder = @import("../terminal/UTF8Decoder.zig");
const unicode = @import("../unicode/main.zig"); const unicode = @import("../unicode/main.zig");
@@ -39,9 +38,6 @@ pub const Mode = enum {
/// Ghostty's table-based approach. /// Ghostty's table-based approach.
table, table,
/// uucode implementation
uucode,
}; };
/// Create a new terminal stream handler for the given arguments. /// Create a new terminal stream handler for the given arguments.
@@ -64,7 +60,6 @@ pub fn benchmark(self: *GraphemeBreak) Benchmark {
.stepFn = switch (self.opts.mode) { .stepFn = switch (self.opts.mode) {
.noop => stepNoop, .noop => stepNoop,
.table => stepTable, .table => stepTable,
.uucode => stepUucode,
}, },
.setupFn = setup, .setupFn = setup,
.teardownFn = teardown, .teardownFn = teardown,
@@ -138,33 +133,6 @@ 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 { test GraphemeBreak {
const testing = std.testing; const testing = std.testing;
const alloc = testing.allocator; const alloc = testing.allocator;

View File

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

View File

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

View File

@@ -25,14 +25,11 @@ pub fn init(b: *std.Build) !GhosttyFrameData {
}); });
const run = b.addRunArtifact(exe); 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 .{ return .{
.exe = exe, .exe = exe,
.output = dir.path(b, "framedata.zig"), .output = run.captureStdOut(),
}; };
} }

View File

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

View File

@@ -1,88 +0,0 @@
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,6 +5,9 @@ const builtin = @import("builtin");
const assert = std.debug.assert; const assert = std.debug.assert;
const buildpkg = @import("main.zig"); const buildpkg = @import("main.zig");
const Config = @import("Config.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; const RunStep = std.Build.Step.Run;
steps: []*std.Build.Step, steps: []*std.Build.Step,
@@ -13,19 +16,6 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
var steps = std.ArrayList(*std.Build.Step).init(b.allocator); var steps = std.ArrayList(*std.Build.Step).init(b.allocator);
errdefer steps.deinit(); 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
terminfo: { terminfo: {
const os_tag = cfg.target.result.os.tag; const os_tag = cfg.target.result.os.tag;
@@ -35,10 +25,13 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
"terminfo"; "terminfo";
// Encode our terminfo // Encode our terminfo
const run = b.addRunArtifact(build_data_exe); var str = std.ArrayList(u8).init(b.allocator);
run.addArg("+terminfo"); defer str.deinit();
const wf = b.addWriteFiles(); try terminfo.ghostty.encode(str.writer());
const source = wf.addCopyFile(run.captureStdOut(), "ghostty.terminfo");
// Write it
var wf = b.addWriteFiles();
const source = wf.add("ghostty.terminfo", str.items);
if (cfg.emit_terminfo) { if (cfg.emit_terminfo) {
const source_install = b.addInstallFile( const source_install = b.addInstallFile(
@@ -137,10 +130,8 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
// Fish shell completions // Fish shell completions
{ {
const run = b.addRunArtifact(build_data_exe);
run.addArg("+fish");
const wf = b.addWriteFiles(); const wf = b.addWriteFiles();
_ = wf.addCopyFile(run.captureStdOut(), "ghostty.fish"); _ = wf.add("ghostty.fish", buildpkg.fish_completions);
const install_step = b.addInstallDirectory(.{ const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(), .source_dir = wf.getDirectory(),
@@ -152,10 +143,8 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
// zsh shell completions // zsh shell completions
{ {
const run = b.addRunArtifact(build_data_exe);
run.addArg("+zsh");
const wf = b.addWriteFiles(); const wf = b.addWriteFiles();
_ = wf.addCopyFile(run.captureStdOut(), "_ghostty"); _ = wf.add("_ghostty", buildpkg.zsh_completions);
const install_step = b.addInstallDirectory(.{ const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(), .source_dir = wf.getDirectory(),
@@ -167,10 +156,8 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
// bash shell completions // bash shell completions
{ {
const run = b.addRunArtifact(build_data_exe);
run.addArg("+bash");
const wf = b.addWriteFiles(); const wf = b.addWriteFiles();
_ = wf.addCopyFile(run.captureStdOut(), "ghostty.bash"); _ = wf.add("ghostty.bash", buildpkg.bash_completions);
const install_step = b.addInstallDirectory(.{ const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(), .source_dir = wf.getDirectory(),
@@ -180,44 +167,39 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
try steps.append(&install_step.step); try steps.append(&install_step.step);
} }
// Vim and Neovim plugin // Vim plugin
{ {
const wf = b.addWriteFiles(); 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(), .source_dir = wf.getDirectory(),
.install_dir = .prefix, .install_dir = .prefix,
.install_subdir = "share/vim/vimfiles", .install_subdir = "share/vim/vimfiles",
}); });
try steps.append(&vim_step.step); try steps.append(&install_step.step);
}
const neovim_step = b.addInstallDirectory(.{ // 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(.{
.source_dir = wf.getDirectory(), .source_dir = wf.getDirectory(),
.install_dir = .prefix, .install_dir = .prefix,
.install_subdir = "share/nvim/site", .install_subdir = "share/nvim/site",
}); });
try steps.append(&neovim_step.step); try steps.append(&install_step.step);
} }
// Sublime syntax highlighting for bat cli tool // Sublime syntax highlighting for bat cli tool
@@ -227,10 +209,8 @@ pub fn init(b: *std.Build, cfg: *const Config) !GhosttyResources {
// the config file within the '~.config/bat' directory // the config file within the '~.config/bat' directory
// (ex: --map-syntax "/Users/user/.config/ghostty/config:Ghostty Config"). // (ex: --map-syntax "/Users/user/.config/ghostty/config:Ghostty Config").
{ {
const run = b.addRunArtifact(build_data_exe);
run.addArg("+sublime");
const wf = b.addWriteFiles(); const wf = b.addWriteFiles();
_ = wf.addCopyFile(run.captureStdOut(), "ghostty.sublime-syntax"); _ = wf.add("ghostty.sublime-syntax", config_sublime_syntax.syntax);
const install_step = b.addInstallDirectory(.{ const install_step = b.addInstallDirectory(.{
.source_dir = wf.getDirectory(), .source_dir = wf.getDirectory(),

View File

@@ -5,11 +5,12 @@ const Config = @import("Config.zig");
const SharedDeps = @import("SharedDeps.zig"); const SharedDeps = @import("SharedDeps.zig");
const GhosttyLib = @import("GhosttyLib.zig"); const GhosttyLib = @import("GhosttyLib.zig");
const XCFrameworkStep = @import("XCFrameworkStep.zig"); const XCFrameworkStep = @import("XCFrameworkStep.zig");
const Target = @import("xcframework.zig").Target;
xcframework: *XCFrameworkStep, xcframework: *XCFrameworkStep,
target: Target, target: Target,
pub const Target = enum { native, universal };
pub fn init( pub fn init(
b: *std.Build, b: *std.Build,
deps: *const SharedDeps, deps: *const SharedDeps,

View File

@@ -1,82 +0,0 @@
//! 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,14 +31,9 @@ pub fn init(b: *std.Build, cfg: *const Config) !HelpStrings {
exe.root_module.addOptions("build_options", options); exe.root_module.addOptions("build_options", options);
const help_run = b.addRunArtifact(exe); 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 .{ return .{
.exe = exe, .exe = exe,
.output = output, .output = help_run.captureStdOut(),
}; };
} }

View File

@@ -1,8 +1,6 @@
const SharedDeps = @This(); const SharedDeps = @This();
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin");
const Config = @import("Config.zig"); const Config = @import("Config.zig");
const HelpStrings = @import("HelpStrings.zig"); const HelpStrings = @import("HelpStrings.zig");
const MetallibStep = @import("MetallibStep.zig"); const MetallibStep = @import("MetallibStep.zig");
@@ -17,26 +15,16 @@ help_strings: HelpStrings,
metallib: ?*MetallibStep, metallib: ?*MetallibStep,
unicode_tables: UnicodeTables, unicode_tables: UnicodeTables,
framedata: GhosttyFrameData, framedata: GhosttyFrameData,
uucode_tables: std.Build.LazyPath,
/// Used to keep track of a list of file sources. /// Used to keep track of a list of file sources.
pub const LazyPathList = std.ArrayList(std.Build.LazyPath); pub const LazyPathList = std.ArrayList(std.Build.LazyPath);
pub fn init(b: *std.Build, cfg: *const Config) !SharedDeps { 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 = .{ var result: SharedDeps = .{
.config = cfg, .config = cfg,
.help_strings = try .init(b, cfg), .help_strings = try .init(b, cfg),
.unicode_tables = try .init(b, uucode_tables), .unicode_tables = try .init(b),
.framedata = try .init(b), .framedata = try .init(b),
.uucode_tables = uucode_tables,
// Setup by retarget // Setup by retarget
.options = undefined, .options = undefined,
@@ -116,25 +104,9 @@ pub fn add(
var static_libs = LazyPathList.init(b.allocator); var static_libs = LazyPathList.init(b.allocator);
errdefer static_libs.deinit(); 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 // Every exe gets build options populated
step.root_module.addOptions("build_options", self.options); step.root_module.addOptions("build_options", self.options);
// Every exe needs the terminal options
self.config.terminalOptions().add(b, step.root_module);
// Freetype // Freetype
_ = b.systemIntegrationOption("freetype", .{}); // Shows it in help _ = b.systemIntegrationOption("freetype", .{}); // Shows it in help
if (self.config.font_backend.hasFreetype()) { if (self.config.font_backend.hasFreetype()) {
@@ -285,7 +257,7 @@ pub fn add(
spirv_cross_dep.module("spirv_cross"), spirv_cross_dep.module("spirv_cross"),
); );
if (b.systemIntegrationOption("spirv-cross", .{})) { if (b.systemIntegrationOption("spirv-cross", .{})) {
step.linkSystemLibrary2("spirv-cross-c-shared", dynamic_link_opts); step.linkSystemLibrary2("spirv-cross", dynamic_link_opts);
} else { } else {
step.linkLibrary(spirv_cross_dep.artifact("spirv_cross")); step.linkLibrary(spirv_cross_dep.artifact("spirv_cross"));
try static_libs.append( try static_libs.append(
@@ -294,6 +266,21 @@ 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 // Sentry
if (self.config.sentry) { if (self.config.sentry) {
if (b.lazyDependency("sentry", .{ if (b.lazyDependency("sentry", .{
@@ -322,13 +309,6 @@ 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. // Wasm we do manually since it is such a different build.
if (step.rootModuleTarget().cpu.arch == .wasm32) { if (step.rootModuleTarget().cpu.arch == .wasm32) {
if (b.lazyDependency("zig_js", .{ if (b.lazyDependency("zig_js", .{
@@ -363,8 +343,35 @@ pub fn add(
step.addIncludePath(b.path("src/apprt/gtk")); step.addIncludePath(b.path("src/apprt/gtk"));
} }
// libcpp is required for various dependencies // C++ files
step.linkLibCpp(); 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. // We always require the system SDK so that our system headers are available.
// This makes things like `os/log.h` available for cross-compiling. // This makes things like `os/log.h` available for cross-compiling.
@@ -403,13 +410,11 @@ pub fn add(
})) |dep| { })) |dep| {
step.root_module.addImport("z2d", dep.module("z2d")); step.root_module.addImport("z2d", dep.module("z2d"));
} }
if (b.lazyDependency("uucode", .{ if (b.lazyDependency("ziglyph", .{
.target = target, .target = target,
.optimize = optimize, .optimize = optimize,
.tables_path = self.uucode_tables,
.build_config_path = b.path("src/build/uucode_config.zig"),
})) |dep| { })) |dep| {
step.root_module.addImport("uucode", dep.module("uucode")); step.root_module.addImport("ziglyph", dep.module("ziglyph"));
} }
if (b.lazyDependency("zf", .{ if (b.lazyDependency("zf", .{
.target = target, .target = target,
@@ -476,10 +481,28 @@ pub fn add(
try static_libs.append(cimgui_dep.artifact("cimgui").getEmittedBin()); 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 // Fonts
{ {
// JetBrains Mono // JetBrains Mono
if (b.lazyDependency("jetbrains_mono", .{})) |jb_mono| { const jb_mono = b.dependency("jetbrains_mono", .{});
step.root_module.addAnonymousImport( step.root_module.addAnonymousImport(
"jetbrains_mono_regular", "jetbrains_mono_regular",
.{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Regular.ttf") }, .{ .root_source_file = jb_mono.path("fonts/ttf/JetBrainsMono-Regular.ttf") },
@@ -504,16 +527,14 @@ pub fn add(
"jetbrains_mono_variable_italic", "jetbrains_mono_variable_italic",
.{ .root_source_file = jb_mono.path("fonts/variable/JetBrainsMono-Italic[wght].ttf") }, .{ .root_source_file = jb_mono.path("fonts/variable/JetBrainsMono-Italic[wght].ttf") },
); );
}
// Symbols-only nerd font // Symbols-only nerd font
if (b.lazyDependency("nerd_fonts_symbols_only", .{})) |nf_symbols| { const nf_symbols = b.dependency("nerd_fonts_symbols_only", .{});
step.root_module.addAnonymousImport( step.root_module.addAnonymousImport(
"nerd_fonts_symbols_only", "nerd_fonts_symbols_only",
.{ .root_source_file = nf_symbols.path("SymbolsNerdFont-Regular.ttf") }, .{ .root_source_file = nf_symbols.path("SymbolsNerdFont-Regular.ttf") },
); );
} }
}
// If we're building an exe then we have additional dependencies. // If we're building an exe then we have additional dependencies.
if (step.kind != .lib) { if (step.kind != .lib) {
@@ -594,20 +615,17 @@ fn addGtkNg(
"plasma_wayland_protocols", "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. // Unwrap or return, there are no more dependencies below.
const wayland_dep = wayland_dep_ orelse break :wayland; const wayland_dep = wayland_dep_ orelse break :wayland;
const wayland_protocols_dep = wayland_protocols_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 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;
const Scanner = zig_wayland_import.Scanner; // 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 = Scanner.create(zig_wayland_dep.builder, .{ const scanner = Scanner.create(zig_wayland_dep.builder, .{
.wayland_xml = wayland_dep.path("protocol/wayland.xml"), .wayland_xml = wayland_dep.path("protocol/wayland.xml"),
.wayland_protocols = wayland_protocols_dep.path(""), .wayland_protocols = wayland_protocols_dep.path(""),
@@ -677,79 +695,6 @@ 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. /// Creates the resources that can be prebuilt for our dist build.
pub fn gtkNgDistResources( pub fn gtkNgDistResources(
b: *std.Build, b: *std.Build,

View File

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

View File

@@ -1,33 +0,0 @@
#--------------------------------------------------------------------
# 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

@@ -1,16 +0,0 @@
#!/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

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

View File

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

View File

@@ -13,13 +13,11 @@ pub const GhosttyDocs = @import("GhosttyDocs.zig");
pub const GhosttyExe = @import("GhosttyExe.zig"); pub const GhosttyExe = @import("GhosttyExe.zig");
pub const GhosttyFrameData = @import("GhosttyFrameData.zig"); pub const GhosttyFrameData = @import("GhosttyFrameData.zig");
pub const GhosttyLib = @import("GhosttyLib.zig"); pub const GhosttyLib = @import("GhosttyLib.zig");
pub const GhosttyLibVt = @import("GhosttyLibVt.zig");
pub const GhosttyResources = @import("GhosttyResources.zig"); pub const GhosttyResources = @import("GhosttyResources.zig");
pub const GhosttyI18n = @import("GhosttyI18n.zig"); pub const GhosttyI18n = @import("GhosttyI18n.zig");
pub const GhosttyXcodebuild = @import("GhosttyXcodebuild.zig"); pub const GhosttyXcodebuild = @import("GhosttyXcodebuild.zig");
pub const GhosttyXCFramework = @import("GhosttyXCFramework.zig"); pub const GhosttyXCFramework = @import("GhosttyXCFramework.zig");
pub const GhosttyWebdata = @import("GhosttyWebdata.zig"); pub const GhosttyWebdata = @import("GhosttyWebdata.zig");
pub const GhosttyZig = @import("GhosttyZig.zig");
pub const HelpStrings = @import("HelpStrings.zig"); pub const HelpStrings = @import("HelpStrings.zig");
pub const SharedDeps = @import("SharedDeps.zig"); pub const SharedDeps = @import("SharedDeps.zig");
pub const UnicodeTables = @import("UnicodeTables.zig"); pub const UnicodeTables = @import("UnicodeTables.zig");
@@ -30,5 +28,10 @@ pub const LipoStep = @import("LipoStep.zig");
pub const MetallibStep = @import("MetallibStep.zig"); pub const MetallibStep = @import("MetallibStep.zig");
pub const XCFrameworkStep = @import("XCFrameworkStep.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 // Helpers
pub const requireZig = @import("zig.zig").requireZig; pub const requireZig = @import("zig.zig").requireZig;

View File

@@ -1,81 +0,0 @@
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

@@ -1,3 +0,0 @@
/// Target for xcframework builds. This is a separate file so that
/// our runtime code doesn't need to import build code.
pub const Target = enum { native, universal };

View File

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

View File

@@ -49,4 +49,7 @@ pub const Wasm = if (!builtin.target.cpu.arch.isWasm()) struct {} else @import("
test { test {
@import("std").testing.refAllDecls(@This()); @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,6 +19,7 @@ const ArenaAllocator = std.heap.ArenaAllocator;
const global_state = &@import("../global.zig").state; const global_state = &@import("../global.zig").state;
const fontpkg = @import("../font/main.zig"); const fontpkg = @import("../font/main.zig");
const inputpkg = @import("../input.zig"); const inputpkg = @import("../input.zig");
const terminal = @import("../terminal/main.zig");
const internal_os = @import("../os/main.zig"); const internal_os = @import("../os/main.zig");
const cli = @import("../cli.zig"); const cli = @import("../cli.zig");
@@ -38,16 +39,6 @@ const RepeatableStringMap = @import("RepeatableStringMap.zig");
pub const Path = @import("path.zig").Path; pub const Path = @import("path.zig").Path;
pub const RepeatablePath = @import("path.zig").RepeatablePath; 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); const log = std.log.scoped(.config);
/// Used on Unixes for some defaults. /// Used on Unixes for some defaults.

View File

@@ -6,11 +6,8 @@
# {[path]s} # {[path]s}
# #
# The template does not set any default options, since Ghostty ships # The template does not set any default options, since Ghostty ships
# with sensible defaults for all options. # with sensible defaults for all options. Users should only need to set
# Note that you should not paste the output of `ghostty +show-config # options that they want to change from the default.
# --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 # Run `ghostty +show-config --default --docs` to view a list of
# all available config options and their default values. # all available config options and their default values.

View File

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

View File

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

View File

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

View File

@@ -2,20 +2,13 @@ const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const assert = std.debug.assert; const assert = std.debug.assert;
/// Same as std.mem.copyForwards/Backwards but prefers libc memmove if it is /// Same as std.mem.copyForwards but prefers libc memmove if it is available
/// available because it is generally much faster. /// because it is generally much faster.
pub inline fn move(comptime T: type, dest: []T, source: []const T) void { pub inline fn move(comptime T: type, dest: []T, source: []const T) void {
if (builtin.link_libc) { if (builtin.link_libc) {
_ = memmove(dest.ptr, source.ptr, source.len * @sizeOf(T)); _ = memmove(dest.ptr, source.ptr, source.len * @sizeOf(T));
} else { } else {
// 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); 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 std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const uucode = @import("uucode"); const ziglyph = @import("ziglyph");
const font = @import("main.zig"); const font = @import("main.zig");
const Atlas = font.Atlas; const Atlas = font.Atlas;
const CodepointMap = font.CodepointMap; 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 // we'll do this multiple times if we recurse, but this is a cached function
// call higher up (GroupCache) so this should be rare. // call higher up (GroupCache) so this should be rare.
const p_mode: Collection.PresentationMode = if (p) |v| .{ .explicit = v } else .{ const p_mode: Collection.PresentationMode = if (p) |v| .{ .explicit = v } else .{
.default = if (uucode.get(.is_emoji_presentation, @intCast(cp))) .default = if (ziglyph.emoji.isEmojiPresentation(@intCast(cp)))
.emoji .emoji
else else
.text, .text,

View File

@@ -1,110 +0,0 @@
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,7 +5,6 @@ const build_config = @import("../build_config.zig");
const library = @import("library.zig"); const library = @import("library.zig");
pub const Atlas = @import("Atlas.zig"); pub const Atlas = @import("Atlas.zig");
pub const Backend = @import("backend.zig").Backend;
pub const discovery = @import("discovery.zig"); pub const discovery = @import("discovery.zig");
pub const embedded = @import("embedded.zig"); pub const embedded = @import("embedded.zig");
pub const face = @import("face.zig"); pub const face = @import("face.zig");
@@ -49,6 +48,115 @@ pub const options: struct {
.backend = if (builtin.target.cpu.arch.isWasm()) .web_canvas else build_config.font_backend, .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. /// The styles that a family can take.
pub const Style = enum(u3) { pub const Style = enum(u3) {
regular = 0, regular = 0,

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,255 +0,0 @@
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);
}

View File

@@ -1,97 +0,0 @@
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));
}
}

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