467 Commits
v1.2.1 ... tip

Author SHA1 Message Date
Mitchell Hashimoto
67ece53423 lib-vt: begin paste utilities exports starting with safe paste (#9068) 2025-10-06 21:13:54 -07:00
Mitchell Hashimoto
bf9f025aec lib-vt: begin paste utilities exports starting with safe paste 2025-10-06 21:09:28 -07:00
Mitchell Hashimoto
5ece02fa76 lib-vt: split header to be more consumable (#9067)
No functionality changes. This just splits our header up.

Mostly driven by AI, hand reviewed:
https://ampcode.com/threads/T-c3f3e668-448b-4aec-9bac-a230b1d2b3c0
2025-10-06 21:06:27 -07:00
Mitchell Hashimoto
725203d494 lib-vt: split header to be more consumable 2025-10-06 20:48:49 -07:00
Jeffrey C. Ollie
3d1977ca43 osc: parse additional OSC 133 options (#9059)
OSC 133;A can have:

- special_key
- click_events

OSC 133;C can have:

- cmdline
- cmdline_url

Notably, they are in use by `fish`. Not sure what other shells currently
use these options.

Note that the options are only parsed. Nothing further is done with them
at this point.
2025-10-06 16:01:34 -05:00
Jeffrey C. Ollie
323dc54d46 fix custom-shader writergate breakage (#9061)
Fixes: #9060
2025-10-06 15:17:45 -05:00
Jeffrey C. Ollie
f72bbb5038 fix custom-shader writergate breakage
Fixes: #9060
2025-10-06 15:03:25 -05:00
Jeffrey C. Ollie
debdf6bf03 osc: parse additional OSC 133 options
OSC 133;A can have:

- special_key
- click_events

OSC 133;C can have:

- cmdline
- cmdline_url

Notably, they are in use by `fish`. Not sure what other shells currently
use these options.

Note that the options are only parsed. Nothing further is done with them
at this point.
2025-10-06 14:52:09 -05:00
Mitchell Hashimoto
39d3af469e update to the latest zf (#9051) 2025-10-06 11:42:13 -07:00
Mitchell Hashimoto
16026f3023 apprt/gtk: only close with no windows active if close delay is off (#9053)
Fixes #9052
2025-10-06 09:19:33 -07:00
Mitchell Hashimoto
e1e5bfc096 apprt/gtk: only close with no windows active if close delay is off
Fixes #9052
2025-10-06 09:17:16 -07:00
Mitchell Hashimoto
e4f0c366ff lib-vt docs: add etags to the pages 2025-10-06 08:48:57 -07:00
Mitchell Hashimoto
d7b9ce76a6 typos 2025-10-06 08:47:02 -07:00
Mitchell Hashimoto
ffbdfbd1e6 prettier 2025-10-06 08:45:25 -07:00
Mitchell Hashimoto
9194d6c496 doxygen: integrate examples into documentation 2025-10-06 08:44:47 -07:00
Mitchell Hashimoto
972dc94386 gtk: use std.Io.Writer to generate runtime CSS (#9050) 2025-10-06 08:30:23 -07:00
Mitchell Hashimoto
48d5fc925f doxygen: better scrollbar styling 2025-10-06 08:28:24 -07:00
Mitchell Hashimoto
992e9e2a6e doxygen: mobile styling 2025-10-06 08:25:44 -07:00
Jeffrey C. Ollie
76d9d731f0 update to the latest zf 2025-10-06 09:53:42 -05:00
Jeffrey C. Ollie
d2ee80bc49 gtk: use std.Io.Writer to generate runtime CSS 2025-10-06 09:39:50 -05:00
Mitchell Hashimoto
86421c9e09 lib-vt: trying to fix up hosted docs 2025-10-05 20:36:22 -07:00
Mitchell Hashimoto
21d545c3b4 doxygen prettier 2025-10-05 20:28:37 -07:00
Mitchell Hashimoto
6ef0be7580 libghostty website: update to use arch for doxygen for latest 2025-10-05 20:26:18 -07:00
Mitchell Hashimoto
f3c1357337 lib-vt: fix dockerfile to include assets for web 2025-10-05 20:18:48 -07:00
Mitchell Hashimoto
a73a67d252 doxygen improvements 2025-10-05 20:16:42 -07:00
Mitchell Hashimoto
ed65401bf8 osc: reorder osc tests and name them consistently (#9042)
No changes in the tests were made, but reordering them and naming them
consistently will makes finding tests easier (there are a LOT).
2025-10-05 19:51:07 -07:00
Mitchell Hashimoto
3fe1828e5e freebsd: fix CI for Zig 0.15 and enable FreeBSD 15.0 (#9039) 2025-10-05 19:50:47 -07:00
Mitchell Hashimoto
0425e5492e build(deps): bump softprops/action-gh-release from 2.3.3 to 2.3.4 (#9041)
Bumps
[softprops/action-gh-release](https://github.com/softprops/action-gh-release)
from 2.3.3 to 2.3.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/releases">softprops/action-gh-release's
releases</a>.</em></p>
<blockquote>
<h2>v2.3.4</h2>
<!-- raw HTML omitted -->
<h2>What's Changed</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix(action): handle 422 already_exists race condition by <a
href="https://github.com/stephenway"><code>@​stephenway</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/665">softprops/action-gh-release#665</a></li>
</ul>
<h3>Other Changes 🔄</h3>
<ul>
<li>chore(deps): bump actions/setup-node from 4.4.0 to 5.0.0 in the
github-actions group by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/656">softprops/action-gh-release#656</a></li>
<li>chore(deps): bump <code>@​types/node</code> from 20.19.11 to
20.19.13 in the npm group by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/655">softprops/action-gh-release#655</a></li>
<li>chore(deps): bump vite from 7.0.0 to 7.1.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/657">softprops/action-gh-release#657</a></li>
<li>chore(deps): bump the npm group across 1 directory with 2 updates by
<a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/662">softprops/action-gh-release#662</a></li>
<li>chore(deps): bump the npm group with 3 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/666">softprops/action-gh-release#666</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/softprops/action-gh-release/compare/v2...v2.3.4">https://github.com/softprops/action-gh-release/compare/v2...v2.3.4</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md">softprops/action-gh-release's
changelog</a>.</em></p>
<blockquote>
<h2>2.3.4</h2>
<h2>What's Changed</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix(action): handle 422 already_exists race condition by <a
href="https://github.com/stephenway"><code>@​stephenway</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/665">softprops/action-gh-release#665</a></li>
</ul>
<h3>Other Changes 🔄</h3>
<ul>
<li>dependency updates</li>
</ul>
<h2>2.3.3</h2>
<h2>What's Changed</h2>
<h3>Exciting New Features 🎉</h3>
<ul>
<li>feat: add input option <code>overwrite_files</code> by <a
href="https://github.com/asfernandes"><code>@​asfernandes</code></a> in
<a
href="https://redirect.github.com/softprops/action-gh-release/pull/343">softprops/action-gh-release#343</a></li>
</ul>
<h3>Other Changes 🔄</h3>
<ul>
<li>dependency updates</li>
</ul>
<h2>2.3.2</h2>
<ul>
<li>fix: revert fs <code>readableWebStream</code> change</li>
</ul>
<h2>2.3.1</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: fix file closing issue by <a
href="https://github.com/WailGree"><code>@​WailGree</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/629">softprops/action-gh-release#629</a></li>
</ul>
<h2>2.3.0</h2>
<ul>
<li>Migrate from jest to vitest</li>
<li>Replace <code>mime</code> with <code>mime-types</code></li>
<li>Bump to use node 24</li>
<li>Dependency updates</li>
</ul>
<h2>2.2.2</h2>
<h2>What's Changed</h2>
<h3>Bug fixes 🐛</h3>
<ul>
<li>fix: updating release draft status from true to false by <a
href="https://github.com/galargh"><code>@​galargh</code></a> in <a
href="https://redirect.github.com/softprops/action-gh-release/pull/316">softprops/action-gh-release#316</a></li>
</ul>
<h3>Other Changes 🔄</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="62c96d0c4e"><code>62c96d0</code></a>
release 2.3.4</li>
<li><a
href="7dc9b8ac0f"><code>7dc9b8a</code></a>
fix(action): handle 422 already_exists race condition (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/665">#665</a>)</li>
<li><a
href="0f0e0b98e9"><code>0f0e0b9</code></a>
chore(deps): bump the npm group with 3 updates (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/666">#666</a>)</li>
<li><a
href="97d42c1b50"><code>97d42c1</code></a>
chore(deps): bump the npm group across 1 directory with 2 updates (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/662">#662</a>)</li>
<li><a
href="19cd0bcd2b"><code>19cd0bc</code></a>
chore(deps): bump vite from 7.0.0 to 7.1.5 (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/657">#657</a>)</li>
<li><a
href="5d1b0b1164"><code>5d1b0b1</code></a>
chore(deps): bump <code>@​types/node</code> from 20.19.11 to 20.19.13 in
the npm group (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/655">#655</a>)</li>
<li><a
href="f6021cf9a4"><code>f6021cf</code></a>
chore(deps): bump actions/setup-node in the github-actions group (<a
href="https://redirect.github.com/softprops/action-gh-release/issues/656">#656</a>)</li>
<li>See full diff in <a
href="6cbd405e2c...62c96d0c4e">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=softprops/action-gh-release&package-manager=github_actions&previous-version=2.3.3&new-version=2.3.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
2025-10-05 19:50:05 -07:00
Mitchell Hashimoto
b5661cc887 linux cgroup: fix initialization (#9043)
`std.Io.Reader.readAlloc` will fail if it can't read all of the bytes
asked for, so use `File.readToEndAlloc` instead.
2025-10-05 19:49:50 -07:00
Jeffrey C. Ollie
d9de5909d9 linux cgroup: also fix controllers()
This fix was found by Claude Code, but I manually reviewed this change
and removed extraneous changes made by the AI tool.

Co-authored-by: moderation <michael@sooper.org>
2025-10-05 21:03:14 -05:00
Jeffrey C. Ollie
a249b3da3a linux cgroup: fix initialization 2025-10-05 20:46:48 -05:00
Jeffrey C. Ollie
f03344b1c6 osc: reorder osc tests and name them consistently 2025-10-05 19:49:21 -05:00
dependabot[bot]
34cb77c9f2 build(deps): bump softprops/action-gh-release from 2.3.3 to 2.3.4
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.3.3 to 2.3.4.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](6cbd405e2c...62c96d0c4e)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.3.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 00:10:09 +00:00
Jeffrey C. Ollie
67357c663d freebsd: add a timeout to the freebsd job 2025-10-05 19:08:20 -05:00
Jeffrey C. Ollie
d6ef048cd7 freebsd: fix CI for Zig 0.15 and enable FreeBSD 15.0 2025-10-05 18:47:54 -05:00
Mitchell Hashimoto
c5ea4a8079 libghostty: use Arch for docs container to get later Doxygen 2025-10-05 15:19:20 -07:00
Mitchell Hashimoto
aeb6647aa6 libghostty docs: use latest Doxygen 2025-10-05 15:04:51 -07:00
Mitchell Hashimoto
fd0851bae7 lib-vt: update documentation with more examples 2025-10-05 14:54:58 -07:00
Mitchell Hashimoto
48f5e4a16d lib-vt: expose key encoding as a C API (#9040)
Example in `example/c-vt-key-encode`, but here is an abridged version:

```c
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>

int main() {
  GhosttyKeyEncoder encoder;
  GhosttyResult result = ghostty_key_encoder_new(NULL, &encoder);
  assert(result == GHOSTTY_SUCCESS);

  ghostty_key_encoder_setopt(encoder, GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS, &(uint8_t){GHOSTTY_KITTY_KEY_ALL});

  GhosttyKeyEvent event;
  result = ghostty_key_event_new(NULL, &event);
  assert(result == GHOSTTY_SUCCESS);
  ghostty_key_event_set_action(event, GHOSTTY_KEY_ACTION_RELEASE);
  ghostty_key_event_set_key(event, GHOSTTY_KEY_CONTROL_LEFT);
  ghostty_key_event_set_mods(event, GHOSTTY_MODS_CTRL);

  char buf[128];
  size_t written = 0;
  result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
  assert(result == GHOSTTY_SUCCESS);

  ghostty_key_event_free(event);
  ghostty_key_encoder_free(encoder);
  return 0;
}
```
2025-10-05 14:44:55 -07:00
Mitchell Hashimoto
61fe78c1d3 lib-vt: expose key encoding as a C API 2025-10-05 14:40:20 -07:00
Mitchell Hashimoto
fa3bc416ab fix:use builtin memmove (#9033) 2025-10-05 08:18:08 -07:00
NikoMalik
ff3a6d0650 fix: do not remove libc memmove until performance comparisons have been conducted 2025-10-05 17:35:58 +03:00
NikoMalik
1c0282d658 fix:use builtin memmove 2025-10-05 12:30:51 +03:00
Mitchell Hashimoto
31ba6534cf input: use std.Io.Writer for key encoder, new API, expose via libghostty (#9030)
This modernizes `KeyEncoder` to a new `std.Io.Writer`-based API.
Additionally, instead of a single struct, it is now an `encode` function
that takes a series of more focused options. This is more idiomatic Zig
while also making it easier to expose via libghostty-vt.

libghostty-vt Zig module also gains access to key encoding APIs. The C
APIs will follow another time.

Converting the KeyEncoder tests was done using AI:
https://ampcode.com/threads/T-9731bbdc-e0a9-41ad-9404-2b781a66ee39
Reviewed and understood.
2025-10-04 20:24:42 -07:00
Mitchell Hashimoto
44496df899 input: use std.Io.Writer for key encoder, new API, expose via libghostty
This modernizes `KeyEncoder` to a new `std.Io.Writer`-based API.
Additionally, instead of a single struct, it is now an `encode` function
that takes a series of more focused options. This is more idiomatic Zig
while also making it easier to expose via libghostty-vt.

libghostty-vt also gains access to key encoding APIs.
2025-10-04 20:19:39 -07:00
Mitchell Hashimoto
abae5422bf Update iTerm2 colorschemes (#9029)
Upstream release:
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/tag/release-20251002-142451-4a5043e
2025-10-04 17:17:27 -07:00
mitchellh
cef99250a7 deps: Update iTerm2 color schemes 2025-10-05 00:16:06 +00:00
Mitchell Hashimoto
503a25653f build: framegen can use self-hosted (#9021)
This was a red herring when I was doing the 0.15 port. It works with
self-hosted just fine.
2025-10-04 14:08:42 -07:00
Mitchell Hashimoto
e1568118ee Move paste encoding to the input package, test, optimize away one alloc (#9028)
This moves our paste logic to `src/input` in preparation for exposing
this as part of libghostty-vt. This yields an immediate benefit of unit
tests for paste encoding.

Additionally, we were able to remove one allocation on every unbracketed
paste path unless the input specifically contains a newline. Unlikely to
be noticable, but nice.

NOTE: This also includes one change in behavior: we no longer encode
`\r\n` and a single `\r`, but as a duplicate `\r\r`. This matches xterm
behavior and I don't think will result in any issues since duplicate
carriage returns should do nothing in well-behaved terminals.
2025-10-04 14:08:26 -07:00
Mitchell Hashimoto
d4dcecb071 Move paste encoding to the input package, test, optimize away one alloc
This moves our paste logic to `src/input` in preparation for exposing
this as part of libghostty-vt. This yields an immediate benefit of
unit tests for paste encoding. 

Additionally, we were able to remove one allocation on every unbracketed
paste path unless the input specifically contains a newline. Unlikely to
be noticable, but nice.

NOTE: This also includes one change in behavior: we no longer encode
`\r\n` and a single `\r`, but as a duplicate `\r\r`. This matches xterm
behavior and I don't think will result in any issues since duplicate
carriage returns should do nothing in well-behaved terminals.
2025-10-04 14:05:32 -07:00
Mitchell Hashimoto
18eee610bc Expand ~ in macos-custom-icon (#9024)
Since #8999, `macos-custom-icon` works when its a fully expanded
absolute path like `/Users/username/dir/icon.icns`, but not when it's
abbreviated as `~/dir/icon.icns`. Users were understandably surprised
and confused by this. This PR adds tilde expansion using `NSString`s
built-in property for this.

Also removed a line from the config docs that seemed erroneous. Given
that the option has a functional default, it seems incorrect to say that
it's required.
2025-10-04 07:18:50 -07:00
Mitchell Hashimoto
271024c982 font: Add comprehensive constraint tests (#9023)
As promised in #8990.

I opted for hardcoded metrics and bounding boxes rather than actually
loading fonts and glyphs, both to avoid backend dependence and limit the
focus to the constraint calculations themselves, and because I wanted to
test a case that isn't exhibited by any of the fonts available in the
repo.

This also fixes an error from #8990, probably due to a botched
cherry-pick or rebase.
2025-10-04 06:17:28 -07:00
Daniel Wennberg
3620132dfc Remove incorrect note from config docs 2025-10-04 00:13:23 -07:00
Daniel Wennberg
0b14026696 Expand ~ in macos-custom-icon 2025-10-04 00:13:23 -07:00
Daniel Wennberg
6bc60b6c64 Add comprehensive constraint tests 2025-10-03 22:30:52 -07:00
Daniel Wennberg
5360aeb8aa Fix botched cherry-pick from #8990 2025-10-03 22:20:45 -07:00
Mitchell Hashimoto
e07415a2e2 build: framegen can use self-hosted
This was a red herring when I was doing the 0.15 port. It works with
self-hosted just fine.
2025-10-03 14:41:05 -07:00
Mitchell Hashimoto
42a38ff672 snap: fix Zig 0.15 install 2025-10-03 14:12:04 -07:00
Mitchell Hashimoto
f052eb435e fix(font): Final font patcher fixes (#8847)
This is my final set of fixes to the font patcher/icon scaling code. It
builds on #8563 and there's not much reason to pay attention here until
that one has been reviewed (the unique changes in this PR only touch the
two `nerd_font_*` files; the other 8 files in the diff are just #8563).
However, I wanted to make sure the full set of changes/fixes I propose
are out in the open, such that any substantial edits by maintainers
(like in #7953) can take into account the full context.

I think this and the related patches should be considered fixes, not
features, so I hope they can be considered for a 1.2.x release.

This PR fixes some bugs in the extraction of scale and alignment rules
from the `font_patcher` script. Roughly in order of importance:

* Nerd fonts apply an offset to some codepoint ranges when extracting
glyphs from their original font (e.g., Font Awesome) and placing them in
a Nerd Font. Rules are specified in terms of the former codepoints, but
must be applied to the latter. This offset was previously not taken into
account, so rules were applied to the wrong glyphs, and some glyphs that
should have rules didn't get any.
* Previously, the rules from every single patch set was included, but
the embedded Symbols Only font doesn't contain all of them. Most
importantly, there's a legacy patch set that only exists for historical
reasons and is never used anymore, which was overwriting some other
rules because of overlapping codepoint ranges. Also, the Symbols Only
font contains no box drawing characters, so those rules should not be
included. With this PR, irrelevant patch sets are filtered out.
* Some patch sets specify overlapping codepoint ranges, though in
reality the original fonts don't actually cover the full ranges and the
overlaps just imply that they're filling each other's gaps. During font
patching, the presence/absence of a glyph at each codepoint in the
original font takes care of the ambiguity. Since we don't have that
information, we need to hardcode which patch set "wins" for each case
(it's not always the latest set in the list). Luckily, there are only
two cases.
* Many glyphs belong to scale groups that should be scaled and aligned
as a unit. However, in `font_patcher`, the scale group is _not_ used for
_horizontal_ alignment, _unless_ the entire scale group has a single
advance width (remember, the original symbol fonts are not monospace).
This PR implements this rule by only setting `relative_width` and
`relative_x` if the group is monospace.

There are some additional tweaks to ensure that each codepoint actually
gets the rule it's supposed to when it belongs to multiple scale groups
or patch sets, and to avoid setting rules for codepoints that don't
exist in the embedded font.
2025-10-03 13:53:04 -07:00
Mitchell Hashimoto
afa3d5e087 macos: avoid any zero-sized content size increments (#9020)
Fixes #9016
2025-10-03 13:52:42 -07:00
Daniel Wennberg
78f1bf1807 Handle font_patcher codepoint range overlaps 2025-10-03 13:50:11 -07:00
Daniel Wennberg
44951d9b1c Handle font_patcher codepoint offsets 2025-10-03 13:50:11 -07:00
Daniel Wennberg
d07237fff5 Skip patchsets and codepoints not in SymbolsNF 2025-10-03 13:50:11 -07:00
Daniel Wennberg
a1b7ea2e71 Add font_patcher's grouped vs individual alignment 2025-10-03 13:50:11 -07:00
Mitchell Hashimoto
21aa70dc8b fix(font): Fix positioning of scaled glyphs that don’t specify alignment (#8990)
Follow-up to #8563, which broke scaling without alignment. This change
recovers the behavior from before #8563, such that a scaled group is
clamped to the constraint width and height if necessary, and otherwise,
scaling does not shift the center of the group bounding box.

As a part of this change, horizontal alignment was rewritten to assume
the face is flush with the left edge of the cell. The cell-to-face
offset in the rendering code is then applied regardless of the value of
`align_horizontal`. This both simplifies the code and improves
consistency, as it ensures that the offset is the same for all
non-bitmap glyphs (rounded in FreeType, not rounded in CoreText). It's
the right thing to do following the align-to-face changes in #8563.
2025-10-03 13:49:48 -07:00
Daniel Wennberg
50bdd3bac6 Align stretched glyphs to cell, not face 2025-10-03 13:46:36 -07:00
Daniel Wennberg
32f8c71be3 Always clamp scaled glyph to cell
Also take padding into account for centered alignment, necessary since
our constraint type allows asymmetric padding.
2025-10-03 13:44:22 -07:00
Daniel Wennberg
7acf617763 fix(font): Anchor scaling at bounding box center 2025-10-03 13:44:22 -07:00
Mitchell Hashimoto
77114d7927 macos: avoid any zero-sized content size increments
Fixes #9016
2025-10-03 13:35:40 -07:00
Mitchell Hashimoto
b99ca6ad97 flush output for our builddata executable (#9019)
Fixes #9018

We were truncated our terminfo causing tmux to not respect some
features.
2025-10-03 13:33:59 -07:00
Mitchell Hashimoto
93c634c866 flush output for our builddata executable
Fixes #9018

We were truncated our terminfo causing tmux to not respect some
features.
2025-10-03 13:32:15 -07:00
Mitchell Hashimoto
fd64b833a4 fix(font): Apply glyph constraints before thickening and centering before quantizing (#8580)
In CoreText, when thickening (font smoothing) is enabled or Ghostty is
synthesizing a bold face, the glyph bounding box is padded to make sure
the thicker glyph can fit. Currently, this happens before applying
constraints (scaling and alignment), which makes the size and position
of constrained glyphs dependent on font size, font thickening strength,
and display DPI.

With this PR, constraints are applied before any other adjustments, and
padding is applied directly to the rasterization canvas without
modifying any metrics.

For consistency, I also moved constraint application above emboldening
in the FreeType code, although under that API, the two operations are
orthogonal as far as I can tell.

Secondly, this PR moves glyph centering above bitmap quantization, as
centering is generally fractional and will therefore undo the quantizing
if done after.

Supersedes #8552.
2025-10-03 12:55:23 -07:00
Daniel Wennberg
f245574087 Fix comment 2025-10-03 12:53:46 -07:00
Daniel Wennberg
5c129205a5 Use correct and consistent pre-constraint glyph rect
In Freetype, measure rect after emboldening, so constraints apply to the
true glyph size like in CoreText.

In CoreText, don't let font smoothing affect the rect (only the canvas).
2025-10-03 12:53:46 -07:00
Daniel Wennberg
96fbff681b Center before quantizing bitmap glyphs 2025-10-03 12:53:46 -07:00
Mitchell Hashimoto
071621a8c2 Fix typos (#9013)
This PR fixes typos I spotted in the project.
2025-10-03 10:04:35 -07:00
Andreas Deininger
a667b740ee Fix typos 2025-10-03 18:52:26 +02:00
Mitchell Hashimoto
f99a6846bc Add update-mirror Nu script to ease mirror updating for deps (#9010)
This adds a new script we can manually run that downloads all the files
that need to be uploaded to the mirror and updates our build.zig.zon.
The upload still happens manually [by me] but this simplifies the task
greatly.
2025-10-03 08:13:45 -07:00
Mitchell Hashimoto
f0eb46ea26 Add update-mirror Nu script to ease mirror updating for deps
This adds a new script we can manually run that downloads all the files
that need to be uploaded to the mirror and updates our build.zig.zon.
The upload still happens manually [by me] but this simplifies the task
greatly.
2025-10-03 07:39:41 -07:00
Mitchell Hashimoto
1c1a56394d apprt/gtk: Zig 0.15 whack a mole 2025-10-03 07:33:58 -07:00
Mitchell Hashimoto
4d97186643 apprt/gtk: fix Zig 0.15 2025-10-03 07:17:35 -07:00
Mitchell Hashimoto
e0cf528576 Zig 0.15 (#9004)
Replaces #8372 

Before merge I'm going to squash this and give @pluiedev coauthor, since
I took a lot of her work. I just have to go through this myself to make
sure I learn all the changes in Zig 0.15, but as I got things, I copy
and pasted her work in. My work is probably less thorough and there are
places we can convert deprecated things, probably, but this results in
green CI.

## Benchmarks

It looks like there are some speed regressions in isolated places. I'm
not sure if this is noise or not, I'm going to keep running some tests.
If someone can check macOS that'd be helpful (my vtebench is down on
macOS atm), cc @qwerasd205 if interested.

On an x86_64 system:


![output](https://github.com/user-attachments/assets/25395c18-2560-45c8-9fd3-d524bc5cbfb8)
2025-10-03 07:12:12 -07:00
Mitchell Hashimoto
569fe92389 fix up merge conflicts 2025-10-03 07:11:48 -07:00
Mitchell Hashimoto
bb98bc744d ci: disable freebsd for now 2025-10-03 07:10:44 -07:00
Mitchell Hashimoto
22caf60263 update a bunch of required Zig versions to 0.15 2025-10-03 07:10:44 -07:00
Mitchell Hashimoto
a41f59837e nix: update to unstable for Zig 0.15 in package 2025-10-03 07:10:44 -07:00
Mitchell Hashimoto
ba100dddff update deps 2025-10-03 07:10:44 -07:00
Mitchell Hashimoto
87b77e1980 ci: cleanup 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
4e3e0ed056 Zig 0.15: Flatpak 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
e1b5464bab Zig 0.15: build snap 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
2af424268a Zig 0.15: emit bench 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
9ec3b1b152 Zig 0.15: webdata 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
f0cfaa9580 zig 0.15: build on macOS 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
0112607532 Zig 0.15: zig build test macOS 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
d59d754e29 Zig 0.15: zig build GTK exe 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
cb295b84a0 Zig 0.15: zig build test 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
3770f97608 terminal: Zig 0.15, lib-vt and test-lib-vt work 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
913d2dfb23 unicode: fix lookup table generation 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
7ec57aeebd Zig 0.15: zig fmt 2025-10-03 07:10:43 -07:00
Mitchell Hashimoto
d02770d292 zig-15: build binary builds 2025-10-03 07:10:41 -07:00
Mitchell Hashimoto
dfa2354fec Implement and use generic approx equality tester (#8979)
Seems like there needs to be a general, easy-to-use solution for
approximate equality testing of containers holding floats (see, e.g.,
https://github.com/ghostty-org/ghostty/pull/8563#pullrequestreview-3281357931).
How's this?
2025-10-03 07:10:16 -07:00
Mitchell Hashimoto
f8ef51fc61 core: add 'command finished' notifications (#8992)
Fixes #8991

Uses OSC 133 esc sequences to keep track of how long commands take to
execute. If the user chooses, commands that take longer than a user
specified limit will trigger a notification. The user can choose between
a bell notification or a desktop notification.
2025-10-03 06:58:29 -07:00
Mitchell Hashimoto
7ac9de7d83 gtk: fix duplicate signal handlers (#9001)
Signal handlers are connected to surface objects in two spots - when a
tab is added to a page and when the split tree changes. This resulted in
duplicate signal handlers being added for each surface. This was most
noticeable when copying the selection to the clipboard - you would see
two "Copied to clipboard" toasts. Ensure that there is only one signal
handler by removing any old ones before adding the new ones.
2025-10-03 06:53:29 -07:00
Mitchell Hashimoto
8ed3a98db2 Fix Weird Behavior in CoreText Shaper (#9002)
You can pretty simply reproduce a crash on `main` in `Debug` mode by
running `printf "مرحبًا \n"` with your primary font set to one that
supports Arabic such as Cascadia Code/Mono or Kawkab Mono, which will
cause CoreText to output the shaped glyphs non-monotonically which hits
the assert we have in the renderer.

In `ReleaseFast` this assert is skipped and because we already moved
ahead to the space glyph (which belongs at the end but is emitted first)
all of the glyphs up to that point are lost. I believe this is probably
the cause of #8280, I tested and this change seems to fix it at least.

Included in this PR is a little optimization: we were allocating buffers
to copy glyphs etc. from runs to every time, even though CoreText
provides `CTRunGet*Ptr` functions which get *pointers* to the internal
storage of these values- these aren't guaranteed to return a usable
pointer but in that case we can always fall back to allocating again.
Also avoided allocation while processing glyphs by ensuring capacity
beforehand immediately after creating the `CTLine`.

The performance impact of this PR is negligible on my machine and
actually seems to be positive, probably due to avoiding allocations if I
had to guess.
2025-10-02 15:36:02 -07:00
Jeffrey C. Ollie
c8ed3031bc gtk: improve signal handler management
Instead of making two separate passes over the surfaces in a split tree
to manage signal handlers, do it in one pass.
2025-10-02 17:22:52 -05:00
Jeffrey C. Ollie
10adef3092 gtk: fix duplicate signal handlers 2025-10-02 17:22:52 -05:00
Qwerasd
efc6e0d673 fix(font/coretext): always prevent shaper from emitting rtl
The solution we had before worked in most cases but there were some
which caused problems still. This is what HarfBuzz's CoreText shaper
backend does, it uses a CTTypesetter with the forced embedding level
attribute. This fixes the failure case I found that was causing non-
monotonic outputs which can have all sorts of unexpected results, and
causes a crash in Debug modes because we assert the monotonicity while
rendering.
2025-10-02 15:32:21 -06:00
Qwerasd
d6063428bd font/coretext: tiny shaper improvements
Reduce potential allocation while processing glyphs by ensuring capacity
in the buffer ahead of time and also using CTRunGet*Ptr functions first
and only allocating for those if that didn't work (it should almost
always work in practice.)
2025-10-02 14:06:58 -06:00
Mitchell Hashimoto
052857b58b fix(config): Make macos-custom-icon null-terminated (#8999)
The config option `macos-custom-icon` wasn't working because, to pass
successfully through the C API to Swift, the string must be
null-terminated.

Fixes
https://discord.com/channels/1005603569187160125/1423192859112116224
2025-10-02 11:44:43 -07:00
Mitchell Hashimoto
16dab3b8dc crash: remove minidump parser (#9000)
We never used it because our minidump files on Linux didn't contain
meaningful information. With Zig's Writergate, let's drop this and
rewrite it later, we can always resurrect it from the git history.

Rejoice @pluiedev
2025-10-02 11:23:45 -07:00
Mitchell Hashimoto
f76dd96c7e crash: remove minidump parser
We never used it because our minidump files on Linux didn't contain
meaningful information. With Zig's Writergate, let's drop this and
rewrite it later, we can always resurrect it from the git history.
2025-10-02 11:09:51 -07:00
Jeffrey C. Ollie
1c23ebc6f1 address review comments 2025-10-02 12:57:53 -05:00
Jeffrey C. Ollie
07124dba64 core: add 'command finished' notifications
Fixes #8991

Uses OSC 133 esc sequences to keep track of how long commands take to
execute. If the user chooses, commands that take longer than a user
specified limit will trigger a notification. The user can choose between
a bell notification or a desktop notification.
2025-10-02 12:40:40 -05:00
Daniel Wennberg
e615b11b2c fix(config): Make macos-custom-icon null-terminated 2025-10-02 10:28:18 -07:00
Mitchell Hashimoto
9c8d2e577e fix(font): Let powerline glyphs be wide (#8994)
#8829 fixed the interaction of Powerline glyphs with other symbols, but
regressed in the handling of the Powerline glyphs themselves by letting
them get caught in an early exit that imposes a constraint width of 1.
This PR fixes the regression and adds corresponding tests. Tried to be
somewhat principled about why the special treatment is warranted, hence
the new helper function `isGraphicsElement`.

**Before**
<img width="270" height="44" alt="Screenshot 2025-10-02 at 00 16 54"
src="https://github.com/user-attachments/assets/9e975434-114c-44d5-a4ed-ac6a954b9d00"
/>

**After**
<img width="270" height="44" alt="Screenshot 2025-10-02 at 00 16 11"
src="https://github.com/user-attachments/assets/20545e74-c9f9-4a6b-9bf0-a7cf1d38c3a0"
/>
2025-10-02 10:08:24 -07:00
Mitchell Hashimoto
f11a4f7a68 Convert framegen to C, add compressed data to source tarball (#8989)
Zig 0.15 removed the ability to compress from the stdlib, which makes
porting our framegen tool to Zig 0.15+ more work than it's worth. We
already depend on and have the ability to build zlib, and Zig is a full
blown C compiler, so let's just use C.

The framegen C program doesn't free any memory, because it is meant to
exit quickly. It otherwise behaves pretty much the same as the old Zig
codebase.

The build scripts were modified to build the C program and run it, but
also to include the framedata in the generated source tarball so that
downstream packagers don't have to do this (although they'll have all
the deps anyways).

**AI disclosure:** The Zig to C conversion was done by Amp. I know C and
reviewed the code. The build system improvements are partially done by
Amp as well but I finished it all out. I've reviewed everything. Full
thread:
https://ampcode.com/threads/T-4e0a80af-3d2a-48d6-bf59-3e2f05eb7673
2025-10-02 06:57:50 -07:00
Daniel Wennberg
85c879f112 fix(font): Let powerline glyphs be wide 2025-10-02 00:12:00 -07:00
Mitchell Hashimoto
1ec74f8e39 Convert framegen to C, add compressed data to source tarball
Zig 0.15 removed the ability to compress from the stdlib, which makes
porting our framegen tool to Zig 0.15+ more work than it's worth. We
already depend on and have the ability to build zlib, and Zig is a full
blown C compiler, so let's just use C.

The framegen C program doesn't free any memory, because it is meant to
exit quickly. It otherwise behaves pretty much the same as the old Zig
codebase.

The build scripts were modified to build the C program and run it, but
also to include the framedata in the generated source tarball so that
downstream packagers don't have to do this (although they'll have all
the deps anyways).
2025-10-01 14:03:49 -07:00
Mitchell Hashimoto
a5aff0e347 feat: add GHOSTTY_BIN_DIR to path via shell integration (#8976)
Closes #8956

Elvish written by Copilot, the rest was written by me with AI
documentation.
2025-10-01 07:52:12 -07:00
Jon Parise
6f596ee7c3 shell-integration: append $GHOSTTY_BIN_DIR to $PATH
For consistency with the termio/Exec.zig implementation, we always
append to the PATH (lowest priority).
2025-10-01 10:42:33 -04:00
Jon Parise
4989f92c71 shell-integration: remove redundant comments
I think the conditions are sufficiently self-descriptive.
2025-10-01 10:27:42 -04:00
Mitchell Hashimoto
d7cfc51a4e build: isolate XCFramework.Target so runtime code doesn't depend on it (#8983)
This fixes the lazyImport importing outside of the build root. The build
root for the build binary is always the root `build.zig` (which we
want), but our `src/build_config.zig` transitively imported SharedDeps
which led to issues with Zig 0.15.

This back ports to main early (outside our Zig 0.15 PR) because its
compatible and will simplify that one.
2025-10-01 07:18:05 -07:00
Mitchell Hashimoto
09e4c1e6f2 build: isolate XCFramework.Target so runtime code doesn't depend on it
This fixes the lazyImport importing outside of the build root. The build
root for the build binary is always the root `build.zig` (which we
want), but our `src/build_config.zig` transitively imported SharedDeps
which led to issues.
2025-10-01 07:04:54 -07:00
Matthew Hrehirchuk
9407e0fd0d fix: cleaned up elvish and fish integrations for bin_dir 2025-09-30 22:26:07 -06:00
Daniel Wennberg
3feff75c99 Add proper Zig stdlib attribution 2025-09-30 13:58:41 -07:00
Daniel Wennberg
26b70e3125 Implement and use generic approx equality tester 2025-09-30 12:38:29 -07:00
Mitchell Hashimoto
f41e61cd31 nuke ziglyph from orbit (#8978)
Since we now use uucode, we don't need ziglyph anymore. Ziglyph was kept
around as a test-only dep so we can verify matching but this is
complicating our Zig 0.15 upgrade because ziglyph doesn't support Zig
0.15. Let's just drop it.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

- Split Window
- Tab Group
- Quick Terminal

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

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

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

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

## Benchmarks

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

Summary:

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

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

Sources:

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

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

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

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

### codepoint-width

data.txt

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

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

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

Arabic

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

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

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

Japanese

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

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

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

English

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

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

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

### grapheme-break

data.txt

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

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

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

Arabic

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

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

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

Japanese

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

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

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

English

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

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

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

### is-symbol

data.txt

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

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

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

Arabic

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

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

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

Japanese

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

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

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

English

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

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

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

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

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

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

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

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

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

---

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

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

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

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

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

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

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

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

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

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

**Points to note**

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

**Implementation details**

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

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

**Guide**

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

- Tahoe


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

- Sequoia 


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

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

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

- Unit tests now tests C ABI mode.

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

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

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

- Unit tests now tests C ABI mode.

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

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

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

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

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

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

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

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

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

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

Cheers

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

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

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

@jcollie 

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

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

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


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=namespacelabs/nscloud-cache-action&package-manager=github_actions&previous-version=1.2.17&new-version=1.2.18)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
2025-09-25 17:12:19 -07:00
dependabot[bot]
fdbf0c6242 build(deps): bump namespacelabs/nscloud-cache-action
Bumps [namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action) from 1.2.17 to 1.2.18.
- [Release notes](https://github.com/namespacelabs/nscloud-cache-action/releases)
- [Commits](a289cf5d2f...7baedde84b)

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

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

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


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cachix/install-nix-action&package-manager=github_actions&previous-version=31.6.2&new-version=31.7.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
2025-09-24 20:24:38 -07:00
dependabot[bot]
74419b2fcf build(deps): bump cachix/install-nix-action from 31.6.2 to 31.7.0
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.6.2 to 31.7.0.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](a809471b5c...9280e7aca8)

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

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

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

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

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

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

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

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

Instead of three parts:

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

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

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

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

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

I have no solid explanation for why this change works.


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

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

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

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

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

## Bikeshed

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

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

ABI compatibility will eventually be important.

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

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

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

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

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

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

Instead of three parts:

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

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

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

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

Per #808, it should be removed.

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

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

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

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

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

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

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

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

## What is `libghostty-vt`? 

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

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

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

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

## In This PR

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

## Future

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

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


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=vmactions/freebsd-vm&package-manager=github_actions&previous-version=1.2.3&new-version=1.2.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
2025-09-21 19:38:54 -07:00
Mitchell Hashimoto
6c160844b9 build(deps): bump cachix/install-nix-action from 31.6.1 to 31.6.2 (#8828)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.6.1 to 31.6.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/cachix/install-nix-action/releases">cachix/install-nix-action's
releases</a>.</em></p>
<blockquote>
<h2>v31.6.2</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.31.1 -&gt; 2.31.2 by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/cachix/install-nix-action/pull/256">cachix/install-nix-action#256</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31...v31.6.2">https://github.com/cachix/install-nix-action/compare/v31...v31.6.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a809471b5c"><code>a809471</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/256">#256</a>
from cachix/create-pull-request/patch</li>
<li><a
href="d5f1c043d0"><code>d5f1c04</code></a>
nix: 2.31.1 -&gt; 2.31.2</li>
<li>See full diff in <a
href="7be5dee142...a809471b5c">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=cachix/install-nix-action&package-manager=github_actions&previous-version=31.6.1&new-version=31.6.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>
2025-09-21 19:38:25 -07:00
Mitchell Hashimoto
1de584f32c xdg: treat empty env vars as not existing (#8830)
Replaces #8786 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



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

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

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

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

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

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

This fixes a Metal validation error when using custom shaders:

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

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

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

This fixes a Metal validation error when using custom shaders:

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

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

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

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

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

Fixes #8709.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

---------

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

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

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

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

View File

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

View File

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

View File

@@ -34,7 +34,7 @@ jobs:
with:
# Important so that build number generation works
fetch-depth: 0
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -163,12 +163,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -188,7 +188,7 @@ jobs:
nix develop -c minisign -S -m ghostty-source.tar.gz -s minisign.key < minisign.password
- name: Update Release
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
uses: softprops/action-gh-release@62c96d0c4e8a889135c1f3a25910db8dbe0e85f7 # v2.3.4
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true
@@ -359,7 +359,7 @@ jobs:
# Update Release
- name: Release
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
uses: softprops/action-gh-release@62c96d0c4e8a889135c1f3a25910db8dbe0e85f7 # v2.3.4
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true
@@ -579,7 +579,6 @@ jobs:
# Finally, we need to "attach the staple" to our executable, which will allow our app to be
# validated by macOS even when an internet connection is not available.
echo "Attach staple"
xcrun stapler staple "Ghostty.dmg"
xcrun stapler staple "macos/build/Release/Ghostty.app"
# Zip up the app
@@ -591,7 +590,7 @@ jobs:
# Update Release
- name: Release
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
uses: softprops/action-gh-release@62c96d0c4e8a889135c1f3a25910db8dbe0e85f7 # v2.3.4
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true
@@ -776,7 +775,7 @@ jobs:
# Update Release
- name: Release
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
uses: softprops/action-gh-release@62c96d0c4e8a889135c1f3a25910db8dbe0e85f7 # v2.3.4
with:
name: 'Ghostty Tip ("Nightly")'
prerelease: true

View File

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

View File

@@ -12,17 +12,21 @@ jobs:
needs:
- build-bench
- build-dist
- build-examples
- build-flatpak
- build-freebsd
- build-libghostty-vt
- build-linux
- build-linux-libghostty
- build-nix
- build-macos
- build-macos-matrix
- build-snap
- build-windows
- test
- test-simd
- test-gtk
- test-sentry-linux
- test-i18n
- test-macos
- pinact
- prettier
@@ -68,14 +72,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -86,6 +90,42 @@ jobs:
- name: Build Benchmarks
run: nix develop -c zig build -Demit-bench
build-examples:
strategy:
fail-fast: false
matrix:
dir: [c-vt, c-vt-key-encode, c-vt-paste, zig-vt]
name: Example ${{ matrix.dir }}
runs-on: namespace-profile-ghostty-sm
needs: test
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Build Example
run: |
cd example/${{ matrix.dir }}
nix develop -c zig build
build-flatpak:
strategy:
fail-fast: false
@@ -99,14 +139,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -118,7 +158,83 @@ jobs:
run: |
nix develop -c \
zig build \
-Dflatpak=true
-Dflatpak
build-snap:
strategy:
fail-fast: false
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 with Snap
run: |
nix develop -c \
zig build \
-Dsnap
build-libghostty-vt:
strategy:
matrix:
target:
[
aarch64-macos,
x86_64-macos,
aarch64-linux,
x86_64-linux,
x86_64-windows,
]
runs-on: namespace-profile-ghostty-sm
needs: test
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Build
run: |
nix develop -c zig build lib-vt \
-Dtarget=${{ matrix.target }} \
-Dsimd=false
build-linux:
strategy:
@@ -135,14 +251,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -164,14 +280,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -197,14 +313,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -216,7 +332,7 @@ jobs:
run: nix build .#ghostty-releasefast
- name: Check version
run: result/bin/ghostty +version | grep -q 'builtin.OptimizeMode.ReleaseFast'
run: result/bin/ghostty +version | grep -q '.ReleaseFast'
- name: Check to see if the binary has been stripped
run: nm result/bin/.ghostty-wrapped 2>&1 | grep -q 'no symbols'
@@ -225,7 +341,7 @@ jobs:
run: nix build .#ghostty-debug
- name: Check version
run: result/bin/ghostty +version | grep -q 'builtin.OptimizeMode.Debug'
run: result/bin/ghostty +version | grep -q '.Debug'
- name: Check to see if the binary has not been stripped
run: nm result/bin/.ghostty-wrapped 2>&1 | grep -q 'main_ghostty.main'
@@ -243,14 +359,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -275,7 +391,7 @@ jobs:
trigger-snap:
if: github.event_name != 'pull_request'
runs-on: namespace-profile-ghostty-xsm
needs: build-dist
needs: [build-dist, build-snap]
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -396,7 +512,7 @@ jobs:
$fileContent = Get-Content -Path "build.zig" -Raw
$pattern = 'buildpkg\.requireZig\("(.*?)"\);'
$zigVersion = [regex]::Match($fileContent, $pattern).Groups[1].Value
$version = "zig-windows-x86_64-$zigVersion"
$version = "zig-x86_64-windows-$zigVersion"
Write-Output $version
$uri = "https://ziglang.org/download/$zigVersion/$version.zip"
Invoke-WebRequest -Uri "$uri" -OutFile ".\zig-windows.zip"
@@ -447,6 +563,8 @@ jobs:
test:
if: github.repository == 'ghostty-org/ghostty'
runs-on: namespace-profile-ghostty-md
outputs:
zig_version: ${{ steps.zig.outputs.version }}
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
@@ -454,15 +572,20 @@ jobs:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Get required Zig version
id: zig
run: |
echo "version=$(sed -n -e 's/^.*requireZig("\(.*\)").*$/\1/p' build.zig)" >> $GITHUB_OUTPUT
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -497,14 +620,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -529,6 +652,41 @@ jobs:
-Dgtk-x11=${{ matrix.x11 }} \
-Dgtk-wayland=${{ matrix.wayland }}
test-simd:
strategy:
fail-fast: false
matrix:
simd: ["true", "false"]
name: Build -Dsimd=${{ matrix.simd }}
runs-on: namespace-profile-ghostty-sm
needs: test
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Test
run: |
nix develop -c zig build test -Dsimd=${{ matrix.simd }}
test-sentry-linux:
strategy:
fail-fast: false
@@ -545,14 +703,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -593,6 +751,41 @@ jobs:
- name: test
run: nix develop -c zig build test --system ${{ steps.deps.outputs.deps }}
test-i18n:
strategy:
fail-fast: false
matrix:
i18n: ["true", "false"]
name: Build -Di18n=${{ matrix.simd }}
runs-on: namespace-profile-ghostty-sm
needs: test
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Test
run: |
nix develop -c zig build -Di18n=${{ matrix.i18n }}
zig-fmt:
if: github.repository == 'ghostty-org/ghostty'
runs-on: namespace-profile-ghostty-xsm
@@ -603,12 +796,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -631,12 +824,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -658,12 +851,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -685,12 +878,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -712,12 +905,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -739,12 +932,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -773,12 +966,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -800,12 +993,12 @@ jobs:
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -835,14 +1028,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -857,6 +1050,7 @@ jobs:
test-debian-13:
name: Test build on Debian 13
runs-on: namespace-profile-ghostty-sm
timeout-minutes: 10
needs: [test, build-dist]
steps:
- name: Install and configure Namespace CLI
@@ -922,14 +1116,14 @@ jobs:
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
uses: namespacelabs/nscloud-cache-action@7baedde84bbf5063413d621f282834bc2654d0c1 # v1.2.18
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@7be5dee1421f63d07e71ce6e0a9f8a4b07c2a487 # v31.6.1
- uses: cachix/install-nix-action@9280e7aca88deada44c930f1e2c78e21c3ae3edd # v31.7.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -954,7 +1148,8 @@ jobs:
matrix:
release:
- "14.3"
# - "15.0" # disable until fixed: https://github.com/vmactions/freebsd-vm/issues/108
- "15.0"
timeout-minutes: 10
steps:
- name: Checkout Ghostty
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
@@ -964,7 +1159,7 @@ jobs:
sudo systemctl start ssh
- name: Set up FreeBSD VM
uses: vmactions/freebsd-vm@05856381fab64eeee9b038a0818f6cec649ca17a # v1.2.3
uses: vmactions/freebsd-vm@487ce35b96fae3e60d45b521735f5aa436ecfade # v1.2.4
with:
release: ${{ matrix.release }}
copyback: false
@@ -975,14 +1170,19 @@ jobs:
devel/gettext \
devel/git \
devel/pkgconf \
ftp/curl \
graphics/wayland \
lang/zig \
security/ca_root_nss \
textproc/hs-pandoc \
x11-fonts/jetbrains-mono \
x11-toolkits/libadwaita \
x11-toolkits/gtk40 \
x11-toolkits/gtk4-layer-shell
curl -L -o /tmp/zig.tar.xz "https://ziglang.org/download/${{ needs.test.outputs.zig_version }}/zig-x86_64-freebsd-${{ needs.test.outputs.zig_version }}.tar.xz" && \
mkdir /opt && \
tar -xf /tmp/zig.tar.xz -C /opt && \
rm /tmp/zig.tar.xz && \
ln -s "/opt/zig-x86_64-freebsd-${{ needs.test.outputs.zig_version }}/zig" /usr/local/bin/zig
run: |
zig env

View File

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

View File

@@ -13,10 +13,18 @@ A file for [guiding coding agents](https://agents.md/).
## Directory Structure
- Shared Zig core: `src/`
- C API: `include/ghostty.h`
- C API: `include`
- macOS app: `macos/`
- GTK (Linux and FreeBSD) app: `src/apprt/gtk`
## libghostty-vt
- Build: `zig build lib-vt`
- Test: `zig build test-lib-vt`
- Test filter: `zig build test-lib-vt -Dtest-filter=<test name>`
- When working on libghostty-vt, do not build the full app.
- For C only changes, don't run the Zig tests. Build all the examples.
## macOS App
- Do not use `xcodebuild`

View File

@@ -184,6 +184,8 @@
/po/ko_KR.UTF-8.po @ghostty-org/ko_KR
/po/he_IL.UTF-8.po @ghostty-org/he_IL
/po/it_IT.UTF-8.po @ghostty-org/it_IT
/po/zh_TW.UTF-8.po @ghostty-org/zh_TW
/po/hr_HR.UTF-8.po @ghostty-org/hr_HR
# Packaging - Snap
/snap/ @ghostty-org/snap

82
Doxyfile Normal file
View File

@@ -0,0 +1,82 @@
# Doxyfile 1.13.2
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "libghostty"
PROJECT_LOGO = images/gnome/64.png
INPUT = include/ghostty
INPUT_ENCODING = UTF-8
RECURSIVE = YES
FILE_PATTERNS = *.h
EXAMPLE_PATH = example
EXAMPLE_RECURSIVE = YES
EXAMPLE_PATTERNS = *
FULL_PATH_NAMES = NO
STRIP_FROM_INC_PATH = include
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
REFERENCES_RELATION = YES
REFERENCED_BY_RELATION = YES
#---------------------------------------------------------------------------
# C API Optimization
#---------------------------------------------------------------------------
# Optimize output for C API documentation
OPTIMIZE_OUTPUT_FOR_C = YES
TYPEDEF_HIDES_STRUCT = YES
HIDE_SCOPE_NAMES = YES
# Clean path names
FULL_PATH_NAMES = NO
STRIP_FROM_PATH = .
STRIP_FROM_INC_PATH = include
# Hide undocumented and internal APIs
HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = YES
EXTRACT_ALL = NO
INTERNAL_DOCS = NO
EXTRACT_PRIVATE = NO
EXTRACT_LOCAL_CLASSES = NO
#---------------------------------------------------------------------------
# HTML Output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = zig-out/share/ghostty/doc/libghostty
HTML_EXTRA_STYLESHEET = dist/doxygen/ghostty.css
HTML_EXTRA_FILES = dist/doxygen/favicon.png \
dist/doxygen/mobile-nav.js
HTML_COLORSTYLE = DARK
HTML_CODE_FOLDING = NO
HTML_HEADER = dist/doxygen/header.html
LAYOUT_FILE = DoxygenLayout.xml
GENERATE_TREEVIEW = YES
HTML_DYNAMIC_SECTIONS = YES
SEARCHENGINE = YES
ALPHABETICAL_INDEX = YES
HTML_TIMESTAMP = NO
DISABLE_INDEX = NO
FULL_SIDEBAR = NO
#---------------------------------------------------------------------------
# Graphs and Diagrams
#---------------------------------------------------------------------------
HAVE_DOT = NO
#---------------------------------------------------------------------------
# Man Output
#---------------------------------------------------------------------------
GENERATE_MAN = YES
MAN_OUTPUT = zig-out/share/man
MAN_EXTENSION = .3
MAN_LINKS = YES
#---------------------------------------------------------------------------
# Other Output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO

247
DoxygenLayout.xml Normal file
View File

@@ -0,0 +1,247 @@
<?xml version="1.0" encoding="UTF-8"?>
<doxygenlayout version="2.0">
<!-- Generated by doxygen 1.14.0 -->
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title=""/>
<tab type="pages" visible="yes" title="" intro=""/>
<tab type="topics" visible="yes" title="" intro=""/>
<tab type="modules" visible="yes" title="API Groups" intro="">
<tab type="modulelist" visible="yes" title="" intro=""/>
<tab type="modulemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="structs" visible="yes" title="Data Types" intro="">
<tab type="structlist" visible="yes" title="" intro=""/>
<tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/>
</tab>
<tab type="files" visible="yes" title="C Headers" intro="">
<tab type="filelist" visible="yes" title="" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
<tab type="examples" visible="yes" title="" intro=""/>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_HEADERFILE"/>
<inheritancegraph visible="yes"/>
<collaborationgraph visible="yes"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes visible="yes" title=""/>
<services visible="yes" title=""/>
<interfaces visible="yes" title=""/>
<publicslots visible="yes" title=""/>
<signals visible="yes" title=""/>
<publicmethods visible="yes" title=""/>
<publicstaticmethods visible="yes" title=""/>
<publicattributes visible="yes" title=""/>
<publicstaticattributes visible="yes" title=""/>
<protectedtypes visible="yes" title=""/>
<protectedslots visible="yes" title=""/>
<protectedmethods visible="yes" title=""/>
<protectedstaticmethods visible="yes" title=""/>
<protectedattributes visible="yes" title=""/>
<protectedstaticattributes visible="yes" title=""/>
<packagetypes visible="yes" title=""/>
<packagemethods visible="yes" title=""/>
<packagestaticmethods visible="yes" title=""/>
<packageattributes visible="yes" title=""/>
<packagestaticattributes visible="yes" title=""/>
<properties visible="yes" title=""/>
<events visible="yes" title=""/>
<privatetypes visible="yes" title=""/>
<privateslots visible="yes" title=""/>
<privatemethods visible="yes" title=""/>
<privatestaticmethods visible="yes" title=""/>
<privateattributes visible="yes" title=""/>
<privatestaticattributes visible="yes" title=""/>
<friends visible="yes" title=""/>
<related visible="yes" title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription visible="yes" title=""/>
<memberdef>
<inlineclasses visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<enums visible="yes" title=""/>
<services visible="yes" title=""/>
<interfaces visible="yes" title=""/>
<constructors visible="yes" title=""/>
<functions visible="yes" title=""/>
<related visible="yes" title=""/>
<variables visible="yes" title=""/>
<properties visible="yes" title=""/>
<events visible="yes" title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<concepts visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<enums visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<properties visible="yes" title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription visible="yes" title=""/>
<memberdef>
<inlineclasses visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<enums visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<properties visible="yes" title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a concept page -->
<concept>
<briefdescription visible="yes"/>
<includes visible="$SHOW_HEADERFILE"/>
<definition visible="yes" title=""/>
<detaileddescription visible="yes" title=""/>
<authorsection visible="yes"/>
</concept>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="yes"/>
<includedbygraph visible="yes"/>
<sourcelink visible="yes"/>
<memberdecl>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<concepts visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<enums visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<properties visible="yes" title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription visible="yes" title=""/>
<memberdef>
<inlineclasses visible="yes" title=""/>
<defines visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<enums visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<properties visible="yes" title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<detaileddescription visible="yes" title=""/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<enums visible="yes" title=""/>
<enumvalues visible="no" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<defines visible="yes" title=""/>
<modules visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<concepts visible="yes" title=""/>
<classes visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<signals visible="yes" title=""/>
<publicslots visible="yes" title=""/>
<protectedslots visible="yes" title=""/>
<privateslots visible="yes" title=""/>
<events visible="yes" title=""/>
<properties visible="yes" title=""/>
<friends visible="yes" title=""/>
<membergroups visible="yes"/>
</memberdecl>
<memberdef>
<pagedocs/>
<inlineclasses visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<enums visible="yes" title=""/>
<enumvalues visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<defines visible="yes" title=""/>
<sequences visible="yes" title=""/>
<dictionaries visible="yes" title=""/>
<signals visible="yes" title=""/>
<publicslots visible="yes" title=""/>
<protectedslots visible="yes" title=""/>
<privateslots visible="yes" title=""/>
<events visible="yes" title=""/>
<properties visible="yes" title=""/>
<friends visible="yes" title=""/>
</memberdef>
<groupgraph visible="yes"/>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a C++20 module page -->
<module>
<briefdescription visible="yes"/>
<exportedmodules visible="yes"/>
<memberdecl>
<concepts visible="yes" title=""/>
<classes visible="yes" title=""/>
<enums visible="yes" title=""/>
<typedefs visible="yes" title=""/>
<functions visible="yes" title=""/>
<variables visible="yes" title=""/>
<membergroups visible="yes" title=""/>
</memberdecl>
<detaileddescription visible="yes" title=""/>
<memberdecl>
<files visible="yes"/>
</memberdecl>
</module>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription visible="yes" title=""/>
</directory>
</doxygenlayout>

View File

@@ -4,26 +4,48 @@ const builtin = @import("builtin");
const buildpkg = @import("src/build/main.zig");
comptime {
buildpkg.requireZig("0.14.0");
buildpkg.requireZig("0.15.1");
}
pub fn build(b: *std.Build) !void {
// This defines all the available build options (e.g. `-D`).
// Works around a Zig but still present in 0.15.1. Remove when fixed.
// https://github.com/ghostty-org/ghostty/issues/8924
try limitCoresForZigBug();
// This defines all the available build options (e.g. `-D`). If you
// want to know what options are available, you can run `--help` or
// you can read `src/build/Config.zig`.
const config = try buildpkg.Config.init(b);
const test_filter = b.option(
[]const u8,
const test_filters = b.option(
[][]const u8,
"test-filter",
"Filter for test. Only applies to Zig tests.",
) orelse &[0][]const u8{};
// Ghostty dependencies used by many artifacts.
const deps = try buildpkg.SharedDeps.init(b, &config);
// The modules exported for Zig consumers of libghostty. If you're
// writing a Zig program that uses libghostty, read this file.
const mod = try buildpkg.GhosttyZig.init(
b,
&config,
&deps,
);
// All our steps which we'll hook up later. The steps are shown
// up here just so that they are more self-documenting.
const libvt_step = b.step("lib-vt", "Build libghostty-vt");
const run_step = b.step("run", "Run the app");
const run_valgrind_step = b.step(
"run-valgrind",
"Run the app under valgrind",
);
const test_step = b.step("test", "Run tests");
const test_lib_vt_step = b.step(
"test-lib-vt",
"Run libghostty-vt tests",
);
const test_valgrind_step = b.step(
"test-valgrind",
"Run tests under valgrind",
@@ -37,10 +59,6 @@ pub fn build(b: *std.Build) !void {
const resources = try buildpkg.GhosttyResources.init(b, &config);
const i18n = if (config.i18n) try buildpkg.GhosttyI18n.init(b, &config) else null;
// Ghostty dependencies used by many artifacts.
const deps = try buildpkg.SharedDeps.init(b, &config);
if (config.emit_helpgen) deps.help_strings.install();
// Ghostty executable, the actual runnable Ghostty program.
const exe = try buildpkg.GhosttyExe.init(b, &config, &deps);
@@ -73,7 +91,7 @@ pub fn build(b: *std.Build) !void {
check_step.dependOn(dist.install_step);
}
// libghostty
// libghostty (internal, big)
const libghostty_shared = try buildpkg.GhosttyLib.initShared(
b,
&deps,
@@ -83,6 +101,17 @@ pub fn build(b: *std.Build) !void {
&deps,
);
// libghostty-vt
const libghostty_vt_shared = try buildpkg.GhosttyLibVt.initShared(
b,
&mod,
);
libghostty_vt_shared.install(libvt_step);
libghostty_vt_shared.install(b.getInstallStep());
// Helpgen
if (config.emit_helpgen) deps.help_strings.install();
// Runtime "none" is libghostty, anything else is an executable.
if (config.app_runtime != .none) {
if (config.emit_exe) {
@@ -185,7 +214,7 @@ pub fn build(b: *std.Build) !void {
run_step.dependOn(&macos_app_native_only.open.step);
// If we have no test filters, install the tests too
if (test_filter == null) {
if (test_filters.len == 0) {
macos_app_native_only.addTestStepDependencies(test_step);
}
}
@@ -216,11 +245,29 @@ pub fn build(b: *std.Build) !void {
run_valgrind_step.dependOn(&run_cmd.step);
}
// Zig module tests
{
const mod_vt_test = b.addTest(.{
.root_module = mod.vt,
.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,
.filters = test_filters,
});
const mod_vt_c_test_run = b.addRunArtifact(mod_vt_c_test);
test_lib_vt_step.dependOn(&mod_vt_c_test_run.step);
}
// Tests
{
// Full unit tests
const test_exe = b.addTest(.{
.name = "ghostty-test",
.filters = if (test_filter) |v| &.{v} else &.{},
.filters = test_filters,
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = config.baselineTarget(),
@@ -229,8 +276,9 @@ pub fn build(b: *std.Build) !void {
.omit_frame_pointer = false,
.unwind_tables = .sync,
}),
// Crash on x86_64 without this
.use_llvm = true,
});
if (config.emit_test_exe) b.installArtifact(test_exe);
_ = try deps.add(test_exe);
@@ -238,6 +286,9 @@ pub fn build(b: *std.Build) !void {
const test_run = b.addRunArtifact(test_exe);
test_step.dependOn(&test_run.step);
// Normal tests always test our libghostty modules
//test_step.dependOn(test_lib_vt_step);
// Valgrind test running
const valgrind_run = b.addSystemCommand(&.{
"valgrind",
@@ -258,3 +309,13 @@ pub fn build(b: *std.Build) !void {
try translations_step.addError("cannot update translations when i18n is disabled", .{});
}
}
// WARNING: Remove this when https://github.com/ghostty-org/ghostty/issues/8924 is resolved!
// Limit ourselves to 32 cpus on Linux because of an upstream Zig bug.
fn limitCoresForZigBug() !void {
if (comptime builtin.os.tag != .linux) return;
const pid = std.os.linux.getpid();
var set: std.bit_set.ArrayBitSet(usize, std.os.linux.CPU_SETSIZE * 8) = .initEmpty();
for (0..32) |cpu| set.set(cpu);
try std.os.linux.sched_setaffinity(pid, &set.masks);
}

View File

@@ -1,62 +1,64 @@
.{
.name = .ghostty,
.version = "1.2.0",
.version = "1.2.1",
.paths = .{""},
.fingerprint = 0x64407a2a0b4147e5,
.minimum_zig_version = "0.15.1",
.dependencies = .{
// Zig libs
.libxev = .{
// mitchellh/libxev
.url = "https://github.com/mitchellh/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz",
.hash = "libxev-0.0.0-86vtc2UaEwDfiTKX3iBI-s_hdzfzWQUarT3MUrmUQl-Q",
.url = "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz",
.hash = "libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs",
.lazy = true,
},
.vaxis = .{
// rockorager/libvaxis
.url = "git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23",
.hash = "vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn",
.url = "https://deps.files.ghostty.org/vaxis-9fc9015d5f147568e18c5e7ca28f15bf8b293760.tar.gz",
.hash = "vaxis-0.5.1-BWNV_O8fCQAeUeVrESVc-2BdXloEXkFqReDJL7Q6XTSZ",
.lazy = true,
},
.z2d = .{
// vancluever/z2d
.url = "https://github.com/vancluever/z2d/archive/refs/tags/v0.8.1.tar.gz",
.hash = "z2d-0.8.1-j5P_Hq8vDwB8ZaDA54-SzESDLF2zznG_zvTHiQNJImZP",
.url = "https://deps.files.ghostty.org/z2d-a1237f6881d99b75abd8a20a934e62e34b44a005.tar.gz",
.hash = "z2d-0.8.2-pre-j5P_HlVRFgCsBTQ3EgUoKbYHx5JMnyH1mHsOSPiafnef",
.lazy = true,
},
.zig_objc = .{
// mitchellh/zig-objc
.url = "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz",
.hash = "zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk",
.url = "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
.hash = "zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK",
.lazy = true,
},
.zig_js = .{
// mitchellh/zig-js
.url = "https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz",
.hash = "N-V-__8AAB9YCQBaZtQjJZVndk-g_GDIK-NTZcIa63bFp9yZ",
.url = "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz",
.hash = "zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi",
.lazy = true,
},
.ziglyph = .{
.url = "https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz",
.hash = "ziglyph-0.11.2-AAAAAHPtHwB4Mbzn1KvOV7Wpjo82NYEc_v0WC8oCLrkf",
.lazy = true,
.uucode = .{
// TODO: currently the use-llvm branch because its broken on self-hosted
.url = "https://deps.files.ghostty.org/uucode-f81f8ef8518b8ec5a7fca30ec5fdbc76cc6197df.tar.gz",
.hash = "uucode-0.1.0-ZZjBPjQHQADuCy1VMWftjrMl3iWqgMpUugWVQJG6_7xT",
},
.zig_wayland = .{
// codeberg ifreund/zig-wayland
.url = "https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz",
.hash = "wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy",
.url = "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
.hash = "wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe",
.lazy = true,
},
.zf = .{
// natecraddock/zf
.url = "https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz",
.hash = "zf-0.10.3-OIRy8aiIAACLrBllz0zjxaH0aOe5oNm3KtEMyCntST-9",
.url = "https://github.com/natecraddock/zf/archive/d2c89a7d6b579981da6c9c8912134cf5a22c7194.tar.gz",
.hash = "zf-0.10.3-OIRy8euIAACn1wj5gnZbqxbAdAKI5JGMeex8zrdPqORg",
.lazy = true,
},
.gobject = .{
// https://github.com/jcollie/ghostty-gobject based on zig_gobject
// Temporary until we generate them at build time automatically.
.url = "https://github.com/jcollie/ghostty-gobject/releases/download/0.15.1-2025-09-04-48-1/ghostty-gobject-0.15.1-2025-09-04-48-1.tar.zst",
.hash = "gobject-0.3.0-Skun7ET3nQAc0LzvO0NAvTiGGnmkF36cnmbeCAF6MB7Z",
.url = "https://deps.files.ghostty.org/gobject-2025-09-20-20-1.tar.zst",
.hash = "gobject-0.3.0-Skun7ET3nQCqJhDL0KnF_X7M4L7o7JePsJBbrYpEr7UV",
.lazy = true,
},
@@ -103,17 +105,19 @@
.jetbrains_mono = .{
.url = "https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz",
.hash = "N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x",
.lazy = true,
},
.nerd_fonts_symbols_only = .{
.url = "https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz",
.hash = "N-V-__8AAMVLTABmYkLqhZPLXnMl-KyN38R8UVYqGrxqO26s",
.lazy = true,
},
// Other
.apple_sdk = .{ .path = "./pkg/apple-sdk" },
.iterm2_themes = .{
.url = "https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz",
.hash = "N-V-__8AANodAwDnyHwhlOv5cVRn2rx_dTvija-wy5YtTw1B",
.url = "https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20251002-142451-4a5043e/ghostty-themes.tgz",
.hash = "N-V-__8AALIsAwDyo88G5mGJGN2lSVmmFMx4YePfUvp_2o3Y",
.lazy = true,
},
},

81
build.zig.zon.json generated
View File

@@ -24,10 +24,10 @@
"url": "https://deps.files.ghostty.org/glslang-12201278a1a05c0ce0b6eb6026c65cd3e9247aa041b1c260324bf29cee559dd23ba1.tar.gz",
"hash": "sha256-FKLtu1Ccs+UamlPj9eQ12/WXFgS0uDPmPmB26MCpl7U="
},
"gobject-0.3.0-Skun7ET3nQAc0LzvO0NAvTiGGnmkF36cnmbeCAF6MB7Z": {
"gobject-0.3.0-Skun7ET3nQCqJhDL0KnF_X7M4L7o7JePsJBbrYpEr7UV": {
"name": "gobject",
"url": "https://github.com/jcollie/ghostty-gobject/releases/download/0.15.1-2025-09-04-48-1/ghostty-gobject-0.15.1-2025-09-04-48-1.tar.zst",
"hash": "sha256-h6aKUerGlX2ATVEeoN03eWaqDqvUmKdedgpxrSoHvrY="
"url": "https://deps.files.ghostty.org/gobject-2025-09-20-20-1.tar.zst",
"hash": "sha256-SXiqGm81aUn6yq1wFXgNTAULdKOHS/Rzkp5OgNkkcXo="
},
"N-V-__8AALiNBAA-_0gprYr92CjrMj1I5bqNu0TSJOnjFNSr": {
"name": "gtk4_layer_shell",
@@ -49,10 +49,10 @@
"url": "https://deps.files.ghostty.org/imgui-1220bc6b9daceaf7c8c60f3c3998058045ba0c5c5f48ae255ff97776d9cd8bfc6402.tar.gz",
"hash": "sha256-oF/QHgTPEat4Hig4fGIdLkIPHmBEyOJ6JeYD6pnveGA="
},
"N-V-__8AANodAwDnyHwhlOv5cVRn2rx_dTvija-wy5YtTw1B": {
"N-V-__8AALIsAwDyo88G5mGJGN2lSVmmFMx4YePfUvp_2o3Y": {
"name": "iterm2_themes",
"url": "https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz",
"hash": "sha256-6rKNFpaUvSbvNZ0/+u0h4I/RRaV5V7xIPQ9y7eNVbCA="
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20251002-142451-4a5043e/ghostty-themes.tgz",
"hash": "sha256-GsEWVt4wMzp6+7N5I+QVuhCVJ70cFrdADwUds59AKnw="
},
"N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x": {
"name": "jetbrains_mono",
@@ -64,10 +64,10 @@
"url": "https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz",
"hash": "sha256-/syVtGzwXo4/yKQUdQ4LparQDYnp/fF16U/wQcrxoDo="
},
"libxev-0.0.0-86vtc2UaEwDfiTKX3iBI-s_hdzfzWQUarT3MUrmUQl-Q": {
"libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs": {
"name": "libxev",
"url": "https://github.com/mitchellh/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz",
"hash": "sha256-KaozYKEhhT/6sInef7/8O/60LDBJN+8QmdLuNY1Gkmc="
"url": "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz",
"hash": "sha256-YAPqa5bkpRihKPkyMn15oRvTCZaxO3O66ymRY3lIfdc="
},
"N-V-__8AAG3RoQEyRC2Vw7Qoro5SYBf62IHn3HjqtNVY6aWK": {
"name": "libxml2",
@@ -109,10 +109,20 @@
"url": "https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz",
"hash": "sha256-/8ZooxDndgfTk/PBizJxXyI9oerExNbgV5oR345rWc8="
},
"vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn": {
"uucode-0.1.0-ZZjBPjQHQADuCy1VMWftjrMl3iWqgMpUugWVQJG6_7xT": {
"name": "uucode",
"url": "https://deps.files.ghostty.org/uucode-f81f8ef8518b8ec5a7fca30ec5fdbc76cc6197df.tar.gz",
"hash": "sha256-VomSYOF8fRJwb/8GtVG/QqR6c95zSkQt4649C/4KXAc="
},
"vaxis-0.5.1-BWNV_BMgCQDXdZzABeY4F_xwgE7nHFtYEP07KgEwJWo8": {
"name": "vaxis",
"url": "git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23",
"hash": "sha256-bNZ3oveT6vPChjimPJ/GGfcdivlAeJdl/xfWM+S/MHY="
"url": "git+https://github.com/rockorager/libvaxis#6eb16bb4190dc074dafaf4f0ce7dadd50e81192a",
"hash": "sha256-5c+TjmiH4071lKI+U8SIJ0M+4ezzcAtLI2ZSfZYdXSA="
},
"vaxis-0.5.1-BWNV_O8fCQAeUeVrESVc-2BdXloEXkFqReDJL7Q6XTSZ": {
"name": "vaxis",
"url": "https://deps.files.ghostty.org/vaxis-9fc9015d5f147568e18c5e7ca28f15bf8b293760.tar.gz",
"hash": "sha256-7H5a0J7uUsrzlO7JNAf/Ussi9WxvmsbyJSmhqvl+rqI="
},
"N-V-__8AAKrHGAAs2shYq8UkE6bGcR1QJtLTyOE_lcosMn6t": {
"name": "wayland",
@@ -129,45 +139,40 @@
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
"hash": "sha256-nkzSCr6W5sTG7enDBXEIhgEm574uLD41UVR2wlC+HBM="
},
"z2d-0.8.1-j5P_Hq8vDwB8ZaDA54-SzESDLF2zznG_zvTHiQNJImZP": {
"z2d-0.8.2-pre-j5P_HlVRFgCsBTQ3EgUoKbYHx5JMnyH1mHsOSPiafnef": {
"name": "z2d",
"url": "https://github.com/vancluever/z2d/archive/refs/tags/v0.8.1.tar.gz",
"hash": "sha256-0DbDKSYA1ejhVx/WbOkwTgD57PNRFcnRviqBh8xpPZ0="
"url": "https://deps.files.ghostty.org/z2d-a1237f6881d99b75abd8a20a934e62e34b44a005.tar.gz",
"hash": "sha256-5/qRZAIh1U42v7jql9W0jr2zzQZtu39DxJPLVrSybJg="
},
"zf-0.10.3-OIRy8aiIAACLrBllz0zjxaH0aOe5oNm3KtEMyCntST-9": {
"zf-0.10.3-OIRy8euIAACn1wj5gnZbqxbAdAKI5JGMeex8zrdPqORg": {
"name": "zf",
"url": "https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz",
"hash": "sha256-3nulNQd/4rZ4paeXJYXwAliNNyRNsIOX/q3z1JB8C7I="
"url": "https://github.com/natecraddock/zf/archive/d2c89a7d6b579981da6c9c8912134cf5a22c7194.tar.gz",
"hash": "sha256-Kaduui4Llb9Fq1lCKLOeG8cWTknjhos8cSTeJ50KP/I="
},
"zg-0.13.4-AAAAAGiZ7QLz4pvECFa_wG4O4TP4FLABHHbemH2KakWM": {
"zg-0.15.1-oGqU3M0-tALZCy7boQS86znlBloyKx6--JriGlY0Paa9": {
"name": "zg",
"url": "git+https://codeberg.org/atman/zg#4a002763419a34d61dcbb1f415821b83b9bf8ddc",
"hash": "sha256-fo3l6cjkrr/godElTGnQzalBsasN7J73IDIRmw7v1gA="
"url": "https://codeberg.org/chaten/zg/archive/749197a3f9d25e211615960c02380a3d659b20f9.tar.gz",
"hash": "sha256-BZhz1nPqxK6hdsJQ66n7Jk4zMgFSGLXm8eU0CX/7mDI="
},
"N-V-__8AAB9YCQBaZtQjJZVndk-g_GDIK-NTZcIa63bFp9yZ": {
"zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi": {
"name": "zig_js",
"url": "https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz",
"hash": "sha256-fyNeCVbC9UAaKJY6JhAZlT0A479M/AKYMPIWEZbDWD0="
"url": "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz",
"hash": "sha256-TCAY5WAV05UEuAkDhq2c6Tk/ODgAhdnDI3O/flb8c6M="
},
"zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk": {
"zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK": {
"name": "zig_objc",
"url": "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz",
"hash": "sha256-o3vl7qfkSi0bKXa6JWuF92qMEGP8Af/shcip5nRo5Nw="
"url": "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
"hash": "sha256-3YSvc3YlNW/NciyzCQnzsujXAmZ89XlxSqfqvArAjsw="
},
"wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy": {
"wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe": {
"name": "zig_wayland",
"url": "https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz",
"hash": "sha256-E77GZ15APYbbO1WzmuJi8eG9/iQFbc2CgkNBxjCLUhk="
"url": "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
"hash": "sha256-TxRrc17Q1Sf1IOO/cdPpP3LD0PpYOujt06SFH3B5Ek4="
},
"zigimg-0.1.0-lly-O6N2EABOxke8dqyzCwhtUCAafqP35zC7wsZ4Ddxj": {
"zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms": {
"name": "zigimg",
"url": "git+https://github.com/TUSF/zigimg#31268548fe3276c0e95f318a6c0d2ab10565b58d",
"hash": "sha256-oblfr2FIzuqq0FLo/RrzCwUX1NJJuT53EwD3nP3KwN0="
},
"ziglyph-0.11.2-AAAAAHPtHwB4Mbzn1KvOV7Wpjo82NYEc_v0WC8oCLrkf": {
"name": "ziglyph",
"url": "https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz",
"hash": "sha256-cse98+Ft8QUjX+P88yyYfaxJOJGQ9M7Ymw7jFxDz89k="
"url": "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz",
"hash": "sha256-LB7Xa6KzVRRUSwwnyWM+y6fDG+kIDjfnoBDJO1obxVM="
},
"N-V-__8AAB0eQwD-0MdOEBmz7intriBReIsIDNlukNVoNu6o": {
"name": "zlib",

90
build.zig.zon.nix generated
View File

@@ -123,11 +123,11 @@ in
};
}
{
name = "gobject-0.3.0-Skun7ET3nQAc0LzvO0NAvTiGGnmkF36cnmbeCAF6MB7Z";
name = "gobject-0.3.0-Skun7ET3nQCqJhDL0KnF_X7M4L7o7JePsJBbrYpEr7UV";
path = fetchZigArtifact {
name = "gobject";
url = "https://github.com/jcollie/ghostty-gobject/releases/download/0.15.1-2025-09-04-48-1/ghostty-gobject-0.15.1-2025-09-04-48-1.tar.zst";
hash = "sha256-h6aKUerGlX2ATVEeoN03eWaqDqvUmKdedgpxrSoHvrY=";
url = "https://deps.files.ghostty.org/gobject-2025-09-20-20-1.tar.zst";
hash = "sha256-SXiqGm81aUn6yq1wFXgNTAULdKOHS/Rzkp5OgNkkcXo=";
};
}
{
@@ -163,11 +163,11 @@ in
};
}
{
name = "N-V-__8AANodAwDnyHwhlOv5cVRn2rx_dTvija-wy5YtTw1B";
name = "N-V-__8AALIsAwDyo88G5mGJGN2lSVmmFMx4YePfUvp_2o3Y";
path = fetchZigArtifact {
name = "iterm2_themes";
url = "https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz";
hash = "sha256-6rKNFpaUvSbvNZ0/+u0h4I/RRaV5V7xIPQ9y7eNVbCA=";
url = "https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20251002-142451-4a5043e/ghostty-themes.tgz";
hash = "sha256-GsEWVt4wMzp6+7N5I+QVuhCVJ70cFrdADwUds59AKnw=";
};
}
{
@@ -187,11 +187,11 @@ in
};
}
{
name = "libxev-0.0.0-86vtc2UaEwDfiTKX3iBI-s_hdzfzWQUarT3MUrmUQl-Q";
name = "libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs";
path = fetchZigArtifact {
name = "libxev";
url = "https://github.com/mitchellh/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz";
hash = "sha256-KaozYKEhhT/6sInef7/8O/60LDBJN+8QmdLuNY1Gkmc=";
url = "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz";
hash = "sha256-YAPqa5bkpRihKPkyMn15oRvTCZaxO3O66ymRY3lIfdc=";
};
}
{
@@ -259,11 +259,27 @@ in
};
}
{
name = "vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn";
name = "uucode-0.1.0-ZZjBPjQHQADuCy1VMWftjrMl3iWqgMpUugWVQJG6_7xT";
path = fetchZigArtifact {
name = "uucode";
url = "https://deps.files.ghostty.org/uucode-f81f8ef8518b8ec5a7fca30ec5fdbc76cc6197df.tar.gz";
hash = "sha256-VomSYOF8fRJwb/8GtVG/QqR6c95zSkQt4649C/4KXAc=";
};
}
{
name = "vaxis-0.5.1-BWNV_BMgCQDXdZzABeY4F_xwgE7nHFtYEP07KgEwJWo8";
path = fetchZigArtifact {
name = "vaxis";
url = "git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23";
hash = "sha256-bNZ3oveT6vPChjimPJ/GGfcdivlAeJdl/xfWM+S/MHY=";
url = "git+https://github.com/rockorager/libvaxis#6eb16bb4190dc074dafaf4f0ce7dadd50e81192a";
hash = "sha256-5c+TjmiH4071lKI+U8SIJ0M+4ezzcAtLI2ZSfZYdXSA=";
};
}
{
name = "vaxis-0.5.1-BWNV_O8fCQAeUeVrESVc-2BdXloEXkFqReDJL7Q6XTSZ";
path = fetchZigArtifact {
name = "vaxis";
url = "https://deps.files.ghostty.org/vaxis-9fc9015d5f147568e18c5e7ca28f15bf8b293760.tar.gz";
hash = "sha256-7H5a0J7uUsrzlO7JNAf/Ussi9WxvmsbyJSmhqvl+rqI=";
};
}
{
@@ -291,67 +307,59 @@ in
};
}
{
name = "z2d-0.8.1-j5P_Hq8vDwB8ZaDA54-SzESDLF2zznG_zvTHiQNJImZP";
name = "z2d-0.8.2-pre-j5P_HlVRFgCsBTQ3EgUoKbYHx5JMnyH1mHsOSPiafnef";
path = fetchZigArtifact {
name = "z2d";
url = "https://github.com/vancluever/z2d/archive/refs/tags/v0.8.1.tar.gz";
hash = "sha256-0DbDKSYA1ejhVx/WbOkwTgD57PNRFcnRviqBh8xpPZ0=";
url = "https://deps.files.ghostty.org/z2d-a1237f6881d99b75abd8a20a934e62e34b44a005.tar.gz";
hash = "sha256-5/qRZAIh1U42v7jql9W0jr2zzQZtu39DxJPLVrSybJg=";
};
}
{
name = "zf-0.10.3-OIRy8aiIAACLrBllz0zjxaH0aOe5oNm3KtEMyCntST-9";
name = "zf-0.10.3-OIRy8euIAACn1wj5gnZbqxbAdAKI5JGMeex8zrdPqORg";
path = fetchZigArtifact {
name = "zf";
url = "https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz";
hash = "sha256-3nulNQd/4rZ4paeXJYXwAliNNyRNsIOX/q3z1JB8C7I=";
url = "https://github.com/natecraddock/zf/archive/d2c89a7d6b579981da6c9c8912134cf5a22c7194.tar.gz";
hash = "sha256-Kaduui4Llb9Fq1lCKLOeG8cWTknjhos8cSTeJ50KP/I=";
};
}
{
name = "zg-0.13.4-AAAAAGiZ7QLz4pvECFa_wG4O4TP4FLABHHbemH2KakWM";
name = "zg-0.15.1-oGqU3M0-tALZCy7boQS86znlBloyKx6--JriGlY0Paa9";
path = fetchZigArtifact {
name = "zg";
url = "git+https://codeberg.org/atman/zg#4a002763419a34d61dcbb1f415821b83b9bf8ddc";
hash = "sha256-fo3l6cjkrr/godElTGnQzalBsasN7J73IDIRmw7v1gA=";
url = "https://codeberg.org/chaten/zg/archive/749197a3f9d25e211615960c02380a3d659b20f9.tar.gz";
hash = "sha256-BZhz1nPqxK6hdsJQ66n7Jk4zMgFSGLXm8eU0CX/7mDI=";
};
}
{
name = "N-V-__8AAB9YCQBaZtQjJZVndk-g_GDIK-NTZcIa63bFp9yZ";
name = "zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi";
path = fetchZigArtifact {
name = "zig_js";
url = "https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz";
hash = "sha256-fyNeCVbC9UAaKJY6JhAZlT0A479M/AKYMPIWEZbDWD0=";
url = "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz";
hash = "sha256-TCAY5WAV05UEuAkDhq2c6Tk/ODgAhdnDI3O/flb8c6M=";
};
}
{
name = "zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk";
name = "zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK";
path = fetchZigArtifact {
name = "zig_objc";
url = "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz";
hash = "sha256-o3vl7qfkSi0bKXa6JWuF92qMEGP8Af/shcip5nRo5Nw=";
url = "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz";
hash = "sha256-3YSvc3YlNW/NciyzCQnzsujXAmZ89XlxSqfqvArAjsw=";
};
}
{
name = "wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy";
name = "wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe";
path = fetchZigArtifact {
name = "zig_wayland";
url = "https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz";
hash = "sha256-E77GZ15APYbbO1WzmuJi8eG9/iQFbc2CgkNBxjCLUhk=";
url = "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz";
hash = "sha256-TxRrc17Q1Sf1IOO/cdPpP3LD0PpYOujt06SFH3B5Ek4=";
};
}
{
name = "zigimg-0.1.0-lly-O6N2EABOxke8dqyzCwhtUCAafqP35zC7wsZ4Ddxj";
name = "zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms";
path = fetchZigArtifact {
name = "zigimg";
url = "git+https://github.com/TUSF/zigimg#31268548fe3276c0e95f318a6c0d2ab10565b58d";
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=";
url = "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz";
hash = "sha256-LB7Xa6KzVRRUSwwnyWM+y6fDG+kIDjfnoBDJO1obxVM=";
};
}
{

25
build.zig.zon.txt generated
View File

@@ -1,20 +1,19 @@
git+https://codeberg.org/atman/zg#4a002763419a34d61dcbb1f415821b83b9bf8ddc
git+https://github.com/TUSF/zigimg#31268548fe3276c0e95f318a6c0d2ab10565b58d
git+https://github.com/rockorager/libvaxis#1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23
https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz
git+https://github.com/rockorager/libvaxis#6eb16bb4190dc074dafaf4f0ce7dadd50e81192a
https://codeberg.org/chaten/zg/archive/749197a3f9d25e211615960c02380a3d659b20f9.tar.gz
https://deps.files.ghostty.org/JetBrainsMono-2.304.tar.gz
https://deps.files.ghostty.org/NerdFontsSymbolsOnly-3.4.0.tar.gz
https://deps.files.ghostty.org/breakpad-b99f444ba5f6b98cac261cbb391d8766b34a5918.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/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/gobject-2025-09-20-20-1.tar.zst
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/highway-66486a10623fa0d72fe91260f96c892e41aceb06.tar.gz
https://deps.files.ghostty.org/imgui-1220bc6b9daceaf7c8c60f3c3998058045ba0c5c5f48ae255ff97776d9cd8bfc6402.tar.gz
https://deps.files.ghostty.org/libpng-1220aa013f0c83da3fb64ea6d327f9173fa008d10e28bc9349eac3463457723b1c66.tar.gz
https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz
https://deps.files.ghostty.org/libxml2-2.11.5.tar.gz
https://deps.files.ghostty.org/oniguruma-1220c15e72eadd0d9085a8af134904d9a0f5dfcbed5f606ad60edc60ebeccd9706bb.tar.gz
https://deps.files.ghostty.org/pixels-12207ff340169c7d40c570b4b6a97db614fe47e0d83b5801a932dcd44917424c8806.tar.gz
@@ -22,14 +21,16 @@ https://deps.files.ghostty.org/plasma_wayland_protocols-12207e0851c12acdeee0991e
https://deps.files.ghostty.org/sentry-1220446be831adcca918167647c06c7b825849fa3fba5f22da394667974537a9c77e.tar.gz
https://deps.files.ghostty.org/spirv_cross-1220fb3b5586e8be67bc3feb34cbe749cf42a60d628d2953632c2f8141302748c8da.tar.gz
https://deps.files.ghostty.org/utfcpp-1220d4d18426ca72fc2b7e56ce47273149815501d0d2395c2a98c726b31ba931e641.tar.gz
https://deps.files.ghostty.org/uucode-f81f8ef8518b8ec5a7fca30ec5fdbc76cc6197df.tar.gz
https://deps.files.ghostty.org/vaxis-9fc9015d5f147568e18c5e7ca28f15bf8b293760.tar.gz
https://deps.files.ghostty.org/wayland-9cb3d7aa9dc995ffafdbdef7ab86a949d0fb0e7d.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/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz
https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz
https://deps.files.ghostty.org/z2d-a1237f6881d99b75abd8a20a934e62e34b44a005.tar.gz
https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz
https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz
https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
https://github.com/jcollie/ghostty-gobject/releases/download/0.15.1-2025-09-04-48-1/ghostty-gobject-0.15.1-2025-09-04-48-1.tar.zst
https://github.com/mitchellh/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz
https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz
https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz
https://github.com/vancluever/z2d/archive/refs/tags/v0.8.1.tar.gz
https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20251002-142451-4a5043e/ghostty-themes.tgz
https://github.com/natecraddock/zf/archive/d2c89a7d6b579981da6c9c8912134cf5a22c7194.tar.gz

BIN
dist/doxygen/favicon.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

18
dist/doxygen/footer.html vendored Normal file
View File

@@ -0,0 +1,18 @@
<!-- HTML footer for doxygen 1.14.0-->
<!-- start footer part -->
<!--BEGIN GENERATE_TREEVIEW-->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
$navpath
<li class="footer">$generatedby <a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion </li>
</ul>
</div>
<!--END GENERATE_TREEVIEW-->
<!--BEGIN !GENERATE_TREEVIEW-->
<hr class="footer"/><address class="footer"><small>
$generatedby&#160;<a href="https://www.doxygen.org/index.html"><img class="footer" src="$relpath^doxygen.svg" width="104" height="31" alt="doxygen"/></a> $doxygenversion
</small></address>
</div><!-- doc-content -->
<!--END !GENERATE_TREEVIEW-->
</body>
</html>

390
dist/doxygen/ghostty.css vendored Normal file
View File

@@ -0,0 +1,390 @@
/**
* Ghostty Doxygen Custom Stylesheet
* Minimal branding customizations for Ghostty colors
*/
/* Ghostty brand color for links and accents - high contrast for dark bg */
a,
a:link {
color: #99b3ff;
}
a:visited {
color: #99b3ff;
}
a:hover {
color: #c2d4ff;
}
/* High contrast text colors */
body,
div.contents,
div.header,
.title,
.summary,
td,
th,
p,
li {
color: #e8e8e8 !important;
}
h1,
h2,
h3,
h4,
h5,
h6,
.groupheader {
color: #ffffff !important;
}
.memtitle,
.memname {
color: #ffffff !important;
}
.memdoc {
color: #e8e8e8 !important;
}
/* Selection color */
::selection {
background: rgba(53, 81, 243, 0.6);
}
/* Modern scrollbar styling for WebKit browsers (Safari, Chrome) */
::-webkit-scrollbar {
width: 14px;
height: 14px;
-webkit-appearance: none;
}
::-webkit-scrollbar-track {
background: #1a1f2e;
border-radius: 8px;
}
::-webkit-scrollbar-thumb {
background: #4a5260;
border-radius: 8px;
border: 3px solid #1a1f2e;
min-height: 40px;
}
::-webkit-scrollbar-thumb:hover {
background: #5a6270;
}
::-webkit-scrollbar-thumb:active {
background: #6a7280;
}
::-webkit-scrollbar-corner {
background: #1a1f2e;
}
/* Firefox scrollbar styling */
* {
scrollbar-width: thin;
scrollbar-color: #404754 #1a1f2e;
}
/* Tree view selected item */
#nav-tree .selected {
background-color: #3551f3 !important;
}
/* Custom syntax highlighting optimized for dark backgrounds with high contrast */
.fragment,
div.line {
color: #f0f0f0 !important;
}
/* Keywords (int, void, const, static, etc.) */
.keyword,
.keywordtype {
color: #ff8be6 !important;
font-weight: 500;
}
/* Control flow (if, else, return, for, while, etc.) */
.keywordflow {
color: #ff8be6 !important;
font-weight: 500;
}
/* Comments */
.comment {
color: #8bc34a !important;
font-style: italic;
}
/* Preprocessor directives (#include, #define, etc.) */
.preprocessor {
color: #ffcc66 !important;
}
/* String and character literals */
.stringliteral,
.charliteral {
color: #b8e986 !important;
}
/* Numbers */
span.charliteral {
color: #d4a5ff !important;
}
/* Function names */
.functionname {
color: #6fe87c !important;
font-weight: 500;
}
/* Line numbers */
span.lineno {
color: #8a8a8a !important;
background-color: transparent !important;
}
span.lineno a {
color: #8a8a8a !important;
background-color: transparent !important;
}
/* Desktop: ensure page-nav maintains default width */
@media screen and (min-width: 768px) {
#page-nav-toggle {
display: none !important;
}
#page-nav {
position: relative !important;
width: 250px !important;
height: auto !important;
right: auto !important;
top: auto !important;
box-shadow: none !important;
}
}
/* Mobile-friendly responsive styles */
@media screen and (max-width: 767px) {
body {
font-size: 14px !important;
}
/* Make navigation tree collapsible on mobile */
#side-nav {
display: none;
}
#doc-content {
margin-left: 0 !important;
margin-right: 0 !important;
}
/* Make right sidebar (page-nav) overlay on mobile */
#page-nav {
position: fixed !important;
top: 0 !important;
right: -280px !important;
width: 280px !important;
height: 100vh !important;
z-index: 10000 !important;
background: #101826 !important;
box-shadow: -2px 0 10px rgba(0, 0, 0, 0.5) !important;
transition: right 0.3s ease !important;
overflow-y: auto !important;
-webkit-overflow-scrolling: touch !important;
}
#page-nav.mobile-open {
right: 0 !important;
}
/* Hamburger menu button for page nav */
#page-nav-toggle {
display: block !important;
position: fixed !important;
top: 10px !important;
right: 15px !important;
z-index: 10001 !important;
width: 40px !important;
height: 40px !important;
background: rgba(53, 81, 243, 0.9) !important;
border: none !important;
border-radius: 5px !important;
cursor: pointer !important;
padding: 8px !important;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3) !important;
}
#page-nav-toggle span {
display: block !important;
width: 24px !important;
height: 3px !important;
background: #fff !important;
margin: 4px 0 !important;
border-radius: 2px !important;
transition: 0.3s !important;
}
/* Mobile overlay backdrop */
#page-nav-backdrop {
display: none !important;
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
background: rgba(0, 0, 0, 0.5) !important;
z-index: 9999 !important;
}
#page-nav-backdrop.active {
display: block !important;
}
/* Improve header and navigation */
#top {
height: auto !important;
}
#titlearea {
padding: 10px !important;
}
#projectname {
font-size: 18px !important;
}
#projectbrief,
#projectnumber {
font-size: 12px !important;
}
/* Make tabs stack better on mobile */
#navrow1,
#navrow2,
#navrow3,
#navrow4 {
overflow-x: auto !important;
white-space: nowrap !important;
-webkit-overflow-scrolling: touch !important;
}
.tablist li {
display: inline-block !important;
}
/* Content adjustments */
.contents {
padding: 10px !important;
width: 100% !important;
box-sizing: border-box !important;
}
.header {
padding: 5px !important;
}
/* Code blocks */
.fragment {
font-size: 12px !important;
overflow-x: auto !important;
-webkit-overflow-scrolling: touch !important;
}
div.line {
font-size: 12px !important;
}
/* Tables */
table {
display: block !important;
overflow-x: auto !important;
-webkit-overflow-scrolling: touch !important;
width: 100% !important;
}
.memberdecls table,
.fieldtable {
font-size: 12px !important;
}
.memtitle {
font-size: 14px !important;
padding: 8px !important;
}
.memname {
font-size: 13px !important;
word-break: break-word !important;
}
.memitem {
margin: 5px 0 !important;
}
/* Search box */
#MSearchBox {
width: 100% !important;
right: 0 !important;
}
/* Reduce padding and margins */
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 10px !important;
margin-bottom: 8px !important;
}
h1 {
font-size: 22px !important;
}
h2 {
font-size: 18px !important;
}
h3 {
font-size: 16px !important;
}
h4 {
font-size: 14px !important;
}
/* Directory/file listings */
.directory .levels span {
display: none !important;
}
.directory .arrow {
margin-right: 5px !important;
}
/* Treeview adjustments */
#nav-tree {
width: 100% !important;
}
}
/* Tablet adjustments */
@media screen and (min-width: 768px) and (max-width: 1024px) {
.contents {
padding: 15px !important;
}
#side-nav {
width: 200px !important;
}
#doc-content {
margin-left: 200px !important;
}
}

77
dist/doxygen/header.html vendored Normal file
View File

@@ -0,0 +1,77 @@
<!-- HTML header for doxygen 1.14.0-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen $doxygenversion"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<!--BEGIN PROJECT_ICON-->
<link rel="icon" href="$relpath^$projecticon" type="image/x-icon" />
<!--END PROJECT_ICON-->
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<!--BEGIN FULL_SIDEBAR-->
<script type="text/javascript">var page_layout=1;</script>
<!--END FULL_SIDEBAR-->
<script type="text/javascript" src="$relpath^jquery.js"></script>
<script type="text/javascript" src="$relpath^dynsections.js"></script>
<!--BEGIN COPY_CLIPBOARD-->
<script type="text/javascript" src="$relpath^clipboard.js"></script>
<!--END COPY_CLIPBOARD-->
$treeview
$search
$mathjax
$darkmode
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
<script type="text/javascript" src="$relpath^mobile-nav.js"></script>
</head>
<body>
<!--BEGIN FULL_SIDEBAR-->
<div id="side-nav" class="ui-resizable side-nav-resizable"><!-- do not remove this div, it is closed by doxygen! -->
<!--END FULL_SIDEBAR-->
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--BEGIN TITLEAREA-->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr id="projectrow">
<!--BEGIN PROJECT_LOGO-->
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"$logosize/></td>
<!--END PROJECT_LOGO-->
<!--BEGIN PROJECT_NAME-->
<td id="projectalign">
<div id="projectname">$projectname<!--BEGIN PROJECT_NUMBER--><span id="projectnumber">&#160;$projectnumber</span><!--END PROJECT_NUMBER-->
</div>
<!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
</td>
<!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME-->
<!--BEGIN PROJECT_BRIEF-->
<td>
<div id="projectbrief">$projectbrief</div>
</td>
<!--END PROJECT_BRIEF-->
<!--END !PROJECT_NAME-->
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN SEARCHENGINE-->
<!--BEGIN !FULL_SIDEBAR-->
<td>$searchbox</td>
<!--END !FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
<!--END DISABLE_INDEX-->
</tr>
<!--BEGIN SEARCHENGINE-->
<!--BEGIN FULL_SIDEBAR-->
<tr><td colspan="2">$searchbox</td></tr>
<!--END FULL_SIDEBAR-->
<!--END SEARCHENGINE-->
</tbody>
</table>
</div>
<!--END TITLEAREA-->
<!-- end header part -->

65
dist/doxygen/mobile-nav.js vendored Normal file
View File

@@ -0,0 +1,65 @@
/**
* Mobile navigation toggle for Doxygen documentation
*/
(function () {
// Only run on mobile devices
function isMobile() {
return window.innerWidth <= 767;
}
function initMobileNav() {
if (!isMobile()) return;
const pageNav = document.getElementById("page-nav");
if (!pageNav) return;
// Create toggle button
const toggleBtn = document.createElement("button");
toggleBtn.id = "page-nav-toggle";
toggleBtn.setAttribute("aria-label", "Toggle page navigation");
toggleBtn.innerHTML = "<span></span><span></span><span></span>";
document.body.appendChild(toggleBtn);
// Create backdrop
const backdrop = document.createElement("div");
backdrop.id = "page-nav-backdrop";
document.body.appendChild(backdrop);
// Toggle function
function toggleNav() {
const isOpen = pageNav.classList.toggle("mobile-open");
backdrop.classList.toggle("active", isOpen);
document.body.style.overflow = isOpen ? "hidden" : "";
}
// Event listeners
toggleBtn.addEventListener("click", toggleNav);
backdrop.addEventListener("click", toggleNav);
// Close on escape key
document.addEventListener("keydown", function (e) {
if (e.key === "Escape" && pageNav.classList.contains("mobile-open")) {
toggleNav();
}
});
}
// Initialize on load and resize
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initMobileNav);
} else {
initMobileNav();
}
window.addEventListener("resize", function () {
const pageNav = document.getElementById("page-nav");
const backdrop = document.getElementById("page-nav-backdrop");
if (!isMobile() && pageNav) {
pageNav.classList.remove("mobile-open");
if (backdrop) backdrop.classList.remove("active");
document.body.style.overflow = "";
}
});
})();

2659
dist/doxygen/stylesheet.css vendored Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,22 @@
# Example: `ghostty-vt` C Key Encoding
This example demonstrates how to use the `ghostty-vt` C library to encode key
events into terminal escape sequences.
This example specifically shows how to:
1. Create a key encoder with the C API
2. Configure Kitty keyboard protocol flags (this example uses KKP)
3. Create and configure a key event
4. Encode the key event into a terminal escape sequence
The example encodes a Ctrl key release event with the Ctrl modifier set,
producing the escape sequence `\x1b[57442;5:3u`.
## Usage
Run the program:
```shell-session
zig build run
```

View File

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

View File

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

View File

@@ -0,0 +1,59 @@
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
int main() {
GhosttyKeyEncoder encoder;
GhosttyResult result = ghostty_key_encoder_new(NULL, &encoder);
assert(result == GHOSTTY_SUCCESS);
// Set kitty flags with all features enabled
ghostty_key_encoder_setopt(encoder, GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS, &(uint8_t){GHOSTTY_KITTY_KEY_ALL});
// Create key event
GhosttyKeyEvent event;
result = ghostty_key_event_new(NULL, &event);
assert(result == GHOSTTY_SUCCESS);
ghostty_key_event_set_action(event, GHOSTTY_KEY_ACTION_RELEASE);
ghostty_key_event_set_key(event, GHOSTTY_KEY_CONTROL_LEFT);
ghostty_key_event_set_mods(event, GHOSTTY_MODS_CTRL);
printf("Encoding event: left ctrl release with all Kitty flags enabled\n");
// Optionally, encode with null buffer to get required size. You can
// skip this step and provide a sufficiently large buffer directly.
// If there isn't enoug hspace, the function will return an out of memory
// error.
size_t required = 0;
result = ghostty_key_encoder_encode(encoder, event, NULL, 0, &required);
assert(result == GHOSTTY_OUT_OF_MEMORY);
printf("Required buffer size: %zu bytes\n", required);
// Encode the key event. We don't use our required size above because
// that was just an example; we know 128 bytes is enough.
char buf[128];
size_t written = 0;
result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
assert(result == GHOSTTY_SUCCESS);
printf("Encoded %zu bytes\n", written);
// Print the encoded sequence (hex and string)
printf("Hex: ");
for (size_t i = 0; i < written; i++) printf("%02x ", (unsigned char)buf[i]);
printf("\n");
printf("String: ");
for (size_t i = 0; i < written; i++) {
if (buf[i] == 0x1b) {
printf("\\x1b");
} else {
printf("%c", buf[i]);
}
}
printf("\n");
ghostty_key_event_free(event);
ghostty_key_encoder_free(encoder);
return 0;
}

View File

@@ -0,0 +1,17 @@
# Example: `ghostty-vt` Paste Safety Check
This contains a simple example of how to use the `ghostty-vt` paste
utilities to check if paste data is safe.
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

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

View File

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

View File

@@ -0,0 +1,31 @@
#include <stdio.h>
#include <string.h>
#include <ghostty/vt.h>
int main() {
// Test safe paste data
const char *safe_data = "hello world";
if (ghostty_paste_is_safe(safe_data, strlen(safe_data))) {
printf("'%s' is safe to paste\n", safe_data);
}
// Test unsafe paste data with newline
const char *unsafe_newline = "rm -rf /\n";
if (!ghostty_paste_is_safe(unsafe_newline, strlen(unsafe_newline))) {
printf("'%s' is UNSAFE - contains newline\n", unsafe_newline);
}
// Test unsafe paste data with bracketed paste end sequence
const char *unsafe_escape = "evil\x1b[201~code";
if (!ghostty_paste_is_safe(unsafe_escape, strlen(unsafe_escape))) {
printf("Data with escape sequence is UNSAFE\n");
}
// Test empty data
const char *empty_data = "";
if (ghostty_paste_is_safe(empty_data, 0)) {
printf("Empty data is safe\n");
}
return 0;
}

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

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

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

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

View File

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

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

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

View File

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

4436
example/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

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

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

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

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

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

View File

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

View File

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

34
flake.lock generated
View File

@@ -36,28 +36,28 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1748189127,
"narHash": "sha256-zRDR+EbbeObu4V2X5QCd2Bk5eltfDlCr5yvhBwUT6pY=",
"rev": "7c43f080a7f28b2774f3b3f43234ca11661bf334",
"lastModified": 315532800,
"narHash": "sha256-YwoXN6fthkakCFD7nXPcUK+rkNr6ZTNTuF8zdGaxZo0=",
"rev": "dc704e6102e76aad573f63b74c742cd96f8f1e6c",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/25.05/nixos-25.05.802491.7c43f080a7f2/nixexprs.tar.xz"
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.11pre870318.dc704e6102e7/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
"url": "https://channels.nixos.org/nixos-25.05/nixexprs.tar.xz"
"url": "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1755972213,
"narHash": "sha256-VYK7aDAv8H1enXn1ECRHmGbeY6RqLnNwUJkOwloIsko=",
"rev": "73e96df7cff5783f45e21342a75a1540c4eddce4",
"lastModified": 1758360447,
"narHash": "sha256-XDY3A83bclygHDtesRoaRTafUd80Q30D/Daf9KSG6bs=",
"rev": "8eaee110344796db060382e15d3af0a9fc396e0e",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/unstable-small/nixos-25.11pre850642.73e96df7cff5/nixexprs.tar.xz"
"url": "https://releases.nixos.org/nixos/unstable/nixos-25.11pre864002.8eaee1103447/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
"url": "https://channels.nixos.org/nixos-unstable-small/nixexprs.tar.xz"
"url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"
}
},
"root": {
@@ -97,11 +97,11 @@
]
},
"locked": {
"lastModified": 1748261582,
"narHash": "sha256-3i0IL3s18hdDlbsf0/E+5kyPRkZwGPbSFngq5eToiAA=",
"lastModified": 1759192380,
"narHash": "sha256-0BWJgt4OSzxCESij5oo8WLWrPZ+1qLp8KUQe32QeV4Q=",
"owner": "mitchellh",
"repo": "zig-overlay",
"rev": "aafb1b093fb838f7a02613b719e85ec912914221",
"rev": "0bcd1401ed43d10f10cbded49624206553e92f57",
"type": "github"
},
"original": {
@@ -115,17 +115,17 @@
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1757167408,
"narHash": "sha256-4XyJ6fmKd9wgJ7vHUQuULYy5ps2gUgkkDk/PrJb2OPY=",
"lastModified": 1758405547,
"narHash": "sha256-WgaDgvIZMPvlZcZrpPMjkaalTBnGF2lTG+62znXctWM=",
"owner": "jcollie",
"repo": "zon2nix",
"rev": "dc78177e2ad28d5a407c9e783ee781bd559d7dd5",
"rev": "bf983aa90ff169372b9fa8c02e57ea75e0b42245",
"type": "github"
},
"original": {
"owner": "jcollie",
"repo": "zon2nix",
"rev": "dc78177e2ad28d5a407c9e783ee781bd559d7dd5",
"rev": "bf983aa90ff169372b9fa8c02e57ea75e0b42245",
"type": "github"
}
}

View File

@@ -5,7 +5,9 @@
# We want to stay as up to date as possible but need to be careful that the
# glibc versions used by our dependencies from Nix are compatible with the
# system glibc that the user is building for.
nixpkgs.url = "https://channels.nixos.org/nixos-25.05/nixexprs.tar.xz";
#
# We are currently on unstable to get Zig 0.15 for our package.nix
nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz";
flake-utils.url = "github:numtide/flake-utils";
# Used for shell.nix
@@ -24,7 +26,7 @@
};
zon2nix = {
url = "github:jcollie/zon2nix?rev=dc78177e2ad28d5a407c9e783ee781bd559d7dd5";
url = "github:jcollie/zon2nix?rev=bf983aa90ff169372b9fa8c02e57ea75e0b42245";
inputs = {
# Don't override nixpkgs until Zig 0.15 is available in the Nix branch
# we are using for "normal" builds.
@@ -47,7 +49,7 @@
pkgs = nixpkgs.legacyPackages.${system};
in {
devShell.${system} = pkgs.callPackage ./nix/devShell.nix {
zig = zig.packages.${system}."0.14.1";
zig = zig.packages.${system}."0.15.1";
wraptest = pkgs.callPackage ./nix/wraptest.nix {};
zon2nix = zon2nix;
};

View File

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

View File

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

View File

@@ -13,12 +13,12 @@ modules:
- chmod a+x /app/zig/zig
sources:
- type: archive
sha256: 24aeeec8af16c381934a6cd7d95c807a8cb2cf7df9fa40d359aa884195c4716c
url: https://ziglang.org/download/0.14.1/zig-x86_64-linux-0.14.1.tar.xz
sha256: c61c5da6edeea14ca51ecd5e4520c6f4189ef5250383db33d01848293bfafe05
url: https://ziglang.org/download/0.15.1/zig-x86_64-linux-0.15.1.tar.xz
only-arches: [x86_64]
- type: archive
sha256: f7a654acc967864f7a050ddacfaa778c7504a0eca8d2b678839c21eea47c992b
url: https://ziglang.org/download/0.14.1/zig-aarch64-linux-0.14.1.tar.xz
sha256: bb4a8d2ad735e7fba764c497ddf4243cb129fece4148da3222a7046d3f1f19fe
url: https://ziglang.org/download/0.15.1/zig-aarch64-linux-0.15.1.tar.xz
only-arches: [aarch64]
- name: bzip2-redirect
@@ -30,19 +30,6 @@ modules:
contents: INPUT(libbz2.so)
dest-filename: libbzip2.so
- name: blueprint-compiler
buildsystem: meson
cleanup:
- "*"
sources:
- type: git
url: https://gitlab.gnome.org/jwestman/blueprint-compiler.git
tag: v0.16.0
commit: 04ef0944db56ab01307a29aaa7303df6067cb3c0
x-checker-data:
type: git
tag-pattern: ^v([\d.]+)$
- name: gtk4-layer-shell
buildsystem: meson
sources:

View File

@@ -31,9 +31,9 @@
},
{
"type": "archive",
"url": "https://github.com/jcollie/ghostty-gobject/releases/download/0.15.1-2025-09-04-48-1/ghostty-gobject-0.15.1-2025-09-04-48-1.tar.zst",
"dest": "vendor/p/gobject-0.3.0-Skun7ET3nQAc0LzvO0NAvTiGGnmkF36cnmbeCAF6MB7Z",
"sha256": "87a68a51eac6957d804d511ea0dd377966aa0eabd498a75e760a71ad2a07beb6"
"url": "https://deps.files.ghostty.org/gobject-2025-09-20-20-1.tar.zst",
"dest": "vendor/p/gobject-0.3.0-Skun7ET3nQCqJhDL0KnF_X7M4L7o7JePsJBbrYpEr7UV",
"sha256": "4978aa1a6f356949facaad7015780d4c050b74a3874bf473929e4e80d924717a"
},
{
"type": "archive",
@@ -61,9 +61,9 @@
},
{
"type": "archive",
"url": "https://deps.files.ghostty.org/ghostty-themes-20250915-162204-b1fe546.tgz",
"dest": "vendor/p/N-V-__8AANodAwDnyHwhlOv5cVRn2rx_dTvija-wy5YtTw1B",
"sha256": "eab28d169694bd26ef359d3ffaed21e08fd145a57957bc483d0f72ede3556c20"
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/releases/download/release-20251002-142451-4a5043e/ghostty-themes.tgz",
"dest": "vendor/p/N-V-__8AALIsAwDyo88G5mGJGN2lSVmmFMx4YePfUvp_2o3Y",
"sha256": "1ac11656de30333a7afbb37923e415ba109527bd1c16b7400f051db39f402a7c"
},
{
"type": "archive",
@@ -79,9 +79,9 @@
},
{
"type": "archive",
"url": "https://github.com/mitchellh/libxev/archive/7f803181b158a10fec8619f793e3b4df515566cb.tar.gz",
"dest": "vendor/p/libxev-0.0.0-86vtc2UaEwDfiTKX3iBI-s_hdzfzWQUarT3MUrmUQl-Q",
"sha256": "29aa3360a121853ffab089de7fbffc3bfeb42c304937ef1099d2ee358d469267"
"url": "https://deps.files.ghostty.org/libxev-34fa50878aec6e5fa8f532867001ab3c36fae23e.tar.gz",
"dest": "vendor/p/libxev-0.0.0-86vtc4IcEwCqEYxEYoN_3KXmc6A9VLcm22aVImfvecYs",
"sha256": "6003ea6b96e4a518a128f932327d79a11bd30996b13b73baeb29916379487dd7"
},
{
"type": "archive",
@@ -131,11 +131,23 @@
"dest": "vendor/p/N-V-__8AAHffAgDU0YQmynL8K35WzkcnMUmBVQHQ0jlcKpjH",
"sha256": "ffc668a310e77607d393f3c18b32715f223da1eac4c4d6e0579a11df8e6b59cf"
},
{
"type": "archive",
"url": "https://deps.files.ghostty.org/uucode-f81f8ef8518b8ec5a7fca30ec5fdbc76cc6197df.tar.gz",
"dest": "vendor/p/uucode-0.1.0-ZZjBPjQHQADuCy1VMWftjrMl3iWqgMpUugWVQJG6_7xT",
"sha256": "56899260e17c7d12706fff06b551bf42a47a73de734a442de3ae3d0bfe0a5c07"
},
{
"type": "git",
"url": "https://github.com/rockorager/libvaxis",
"commit": "1f41c121e8fc153d9ce8c6eb64b2bbab68ad7d23",
"dest": "vendor/p/vaxis-0.1.0-BWNV_FUICQAFZnTCL11TUvnUr1Y0_ZdqtXHhd51d76Rn"
"commit": "6eb16bb4190dc074dafaf4f0ce7dadd50e81192a",
"dest": "vendor/p/vaxis-0.5.1-BWNV_BMgCQDXdZzABeY4F_xwgE7nHFtYEP07KgEwJWo8"
},
{
"type": "archive",
"url": "https://deps.files.ghostty.org/vaxis-9fc9015d5f147568e18c5e7ca28f15bf8b293760.tar.gz",
"dest": "vendor/p/vaxis-0.5.1-BWNV_O8fCQAeUeVrESVc-2BdXloEXkFqReDJL7Q6XTSZ",
"sha256": "ec7e5ad09eee52caf394eec93407ff52cb22f56c6f9ac6f22529a1aaf97eaea2"
},
{
"type": "archive",
@@ -157,51 +169,45 @@
},
{
"type": "archive",
"url": "https://github.com/vancluever/z2d/archive/refs/tags/v0.8.1.tar.gz",
"dest": "vendor/p/z2d-0.8.1-j5P_Hq8vDwB8ZaDA54-SzESDLF2zznG_zvTHiQNJImZP",
"sha256": "d036c3292600d5e8e1571fd66ce9304e00f9ecf35115c9d1be2a8187cc693d9d"
"url": "https://deps.files.ghostty.org/z2d-a1237f6881d99b75abd8a20a934e62e34b44a005.tar.gz",
"dest": "vendor/p/z2d-0.8.2-pre-j5P_HlVRFgCsBTQ3EgUoKbYHx5JMnyH1mHsOSPiafnef",
"sha256": "e7fa91640221d54e36bfb8ea97d5b48ebdb3cd066dbb7f43c493cb56b4b26c98"
},
{
"type": "archive",
"url": "https://github.com/natecraddock/zf/archive/7aacbe6d155d64d15937ca95ca6c014905eb531f.tar.gz",
"dest": "vendor/p/zf-0.10.3-OIRy8aiIAACLrBllz0zjxaH0aOe5oNm3KtEMyCntST-9",
"sha256": "de7ba535077fe2b678a5a7972585f002588d37244db08397feadf3d4907c0bb2"
},
{
"type": "git",
"url": "https://codeberg.org/atman/zg",
"commit": "4a002763419a34d61dcbb1f415821b83b9bf8ddc",
"dest": "vendor/p/zg-0.13.4-AAAAAGiZ7QLz4pvECFa_wG4O4TP4FLABHHbemH2KakWM"
"url": "https://github.com/natecraddock/zf/archive/d2c89a7d6b579981da6c9c8912134cf5a22c7194.tar.gz",
"dest": "vendor/p/zf-0.10.3-OIRy8euIAACn1wj5gnZbqxbAdAKI5JGMeex8zrdPqORg",
"sha256": "29a76eba2e0b95bf45ab594228b39e1bc7164e49e3868b3c7124de279d0a3ff2"
},
{
"type": "archive",
"url": "https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz",
"dest": "vendor/p/N-V-__8AAB9YCQBaZtQjJZVndk-g_GDIK-NTZcIa63bFp9yZ",
"sha256": "7f235e0956c2f5401a28963a261019953d00e3bf4cfc029830f2161196c3583d"
"url": "https://codeberg.org/chaten/zg/archive/749197a3f9d25e211615960c02380a3d659b20f9.tar.gz",
"dest": "vendor/p/zg-0.15.1-oGqU3M0-tALZCy7boQS86znlBloyKx6--JriGlY0Paa9",
"sha256": "059873d673eac4aea176c250eba9fb264e3332015218b5e6f1e534097ffb9832"
},
{
"type": "archive",
"url": "https://github.com/mitchellh/zig-objc/archive/c9e917a4e15a983b672ca779c7985d738a2d517c.tar.gz",
"dest": "vendor/p/zig_objc-0.0.0-Ir_SpwsPAQBJgi9YRm2ubJMfdoysSq5gKpsIj3izQ8Zk",
"sha256": "a37be5eea7e44a2d1b2976ba256b85f76a8c1063fc01ffec85c8a9e67468e4dc"
"url": "https://deps.files.ghostty.org/zig_js-04db83c617da1956ac5adc1cb9ba1e434c1cb6fd.tar.gz",
"dest": "vendor/p/zig_js-0.0.0-rjCAV-6GAADxFug7rDmPH-uM_XcnJ5NmuAMJCAscMjhi",
"sha256": "4c2018e56015d39504b8090386ad9ce9393f38380085d9c32373bf7e56fc73a3"
},
{
"type": "archive",
"url": "https://codeberg.org/ifreund/zig-wayland/archive/f3c5d503e540ada8cbcb056420de240af0c094f7.tar.gz",
"dest": "vendor/p/wayland-0.4.0-dev-lQa1kjfIAQCmhhQu3xF0KH-94-TzeMXOqfnP0-Dg6Wyy",
"sha256": "13bec6675e403d86db3b55b39ae262f1e1bdfe24056dcd82824341c6308b5219"
},
{
"type": "git",
"url": "https://github.com/TUSF/zigimg",
"commit": "31268548fe3276c0e95f318a6c0d2ab10565b58d",
"dest": "vendor/p/zigimg-0.1.0-lly-O6N2EABOxke8dqyzCwhtUCAafqP35zC7wsZ4Ddxj"
"url": "https://deps.files.ghostty.org/zig_objc-f356ed02833f0f1b8e84d50bed9e807bf7cdc0ae.tar.gz",
"dest": "vendor/p/zig_objc-0.0.0-Ir_Sp5gTAQCvxxR7oVIrPXxXwsfKgVP7_wqoOQrZjFeK",
"sha256": "dd84af737625356fcd722cb30909f3b2e8d702667cf579714aa7eabc0ac08ecc"
},
{
"type": "archive",
"url": "https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz",
"dest": "vendor/p/ziglyph-0.11.2-AAAAAHPtHwB4Mbzn1KvOV7Wpjo82NYEc_v0WC8oCLrkf",
"sha256": "72c7bdf3e16df105235fe3fcf32c987dac49389190f4ced89b0ee31710f3f3d9"
"url": "https://deps.files.ghostty.org/zig_wayland-1b5c038ec10da20ed3a15b0b2a6db1c21383e8ea.tar.gz",
"dest": "vendor/p/wayland-0.5.0-dev-lQa1khrMAQDJDwYFKpdH3HizherB7sHo5dKMECfvxQHe",
"sha256": "4f146b735ed0d527f520e3bf71d3e93f72c3d0fa583ae8edd3a4851f7079124e"
},
{
"type": "archive",
"url": "https://github.com/ivanstepanovftw/zigimg/archive/d7b7ab0ba0899643831ef042bd73289510b39906.tar.gz",
"dest": "vendor/p/zigimg-0.1.0-8_eo2vHnEwCIVW34Q14Ec-xUlzIoVg86-7FU2ypPtxms",
"sha256": "2c1ed76ba2b35514544b0c27c9633ecba7c31be9080e37e7a010c93b5a1bc553"
},
{
"type": "archive",

View File

@@ -353,6 +353,7 @@ typedef struct {
typedef struct {
const char* ptr;
uintptr_t len;
bool sentinel;
} ghostty_string_s;
typedef struct {
@@ -732,6 +733,14 @@ typedef struct {
int8_t progress;
} ghostty_action_progress_report_s;
// apprt.action.CommandFinished.C
typedef struct {
// -1 if no exit code was reported, otherwise 0-255
int16_t exit_code;
// number of nanoseconds that command was running for
uint64_t duration;
} ghostty_action_command_finished_s;
// apprt.Action.Key
typedef enum {
GHOSTTY_ACTION_QUIT,
@@ -787,6 +796,7 @@ typedef enum {
GHOSTTY_ACTION_SHOW_CHILD_EXITED,
GHOSTTY_ACTION_PROGRESS_REPORT,
GHOSTTY_ACTION_SHOW_ON_SCREEN_KEYBOARD,
GHOSTTY_ACTION_COMMAND_FINISHED,
} ghostty_action_tag_e;
typedef union {
@@ -818,6 +828,7 @@ typedef union {
ghostty_action_close_tab_mode_e close_tab_mode;
ghostty_surface_message_childexited_s child_exited;
ghostty_action_progress_report_s progress_report;
ghostty_action_command_finished_s command_finished;
} ghostty_action_u;
typedef struct {

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

@@ -0,0 +1,77 @@
/**
* @file vt.h
*
* libghostty-vt - Virtual terminal emulator 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 Emulator Library
*
* 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, maintaining terminal state,
* encoding input events, etc. 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 key "Key Encoding" - Encode key events into terminal sequences
* - @ref osc "OSC Parser" - Parse OSC (Operating System Command) sequences
* - @ref paste "Paste Utilities" - Validate paste data safety
* - @ref allocator "Memory Management" - Memory management and custom allocators
*
* @section examples_sec Examples
*
* Complete working examples:
* - @ref c-vt/src/main.c - OSC parser example
* - @ref c-vt-key-encode/src/main.c - Key encoding example
* - @ref c-vt-paste/src/main.c - Paste safety check example
*
*/
/** @example c-vt/src/main.c
* This example demonstrates how to use the OSC parser to parse an OSC sequence,
* extract command information, and retrieve command-specific data like window titles.
*/
/** @example c-vt-key-encode/src/main.c
* This example demonstrates how to use the key encoder to convert key events
* into terminal escape sequences using the Kitty keyboard protocol.
*/
/** @example c-vt-paste/src/main.c
* This example demonstrates how to use the paste utilities to check if
* paste data is safe before sending it to the terminal.
*/
#ifndef GHOSTTY_VT_H
#define GHOSTTY_VT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ghostty/vt/result.h>
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/osc.h>
#include <ghostty/vt/key.h>
#include <ghostty/vt/paste.h>
#ifdef __cplusplus
}
#endif
#endif /* GHOSTTY_VT_H */

View File

@@ -0,0 +1,196 @@
/**
* @file allocator.h
*
* Memory management interface for libghostty-vt.
*/
#ifndef GHOSTTY_VT_ALLOCATOR_H
#define GHOSTTY_VT_ALLOCATOR_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
/** @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 GhosttyAllocator {
/**
* 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;
/** @} */
#endif /* GHOSTTY_VT_ALLOCATOR_H */

80
include/ghostty/vt/key.h Normal file
View File

@@ -0,0 +1,80 @@
/**
* @file key.h
*
* Key encoding module - encode key events into terminal escape sequences.
*/
#ifndef GHOSTTY_VT_KEY_H
#define GHOSTTY_VT_KEY_H
/** @defgroup key Key Encoding
*
* Utilities for encoding key events into terminal escape sequences,
* supporting both legacy encoding as well as Kitty Keyboard Protocol.
*
* ## Basic Usage
*
* 1. Create an encoder instance with ghostty_key_encoder_new()
* 2. Configure encoder options with ghostty_key_encoder_setopt().
* 3. For each key event:
* - Create a key event with ghostty_key_event_new()
* - Set event properties (action, key, modifiers, etc.)
* - Encode with ghostty_key_encoder_encode()
* - Free the event with ghostty_key_event_free()
* - Note: You can also reuse the same key event multiple times by
* changing its properties.
* 4. Free the encoder with ghostty_key_encoder_free() when done
*
* ## Example
*
* @code{.c}
* #include <assert.h>
* #include <stdio.h>
* #include <ghostty/vt.h>
*
* int main() {
* // Create encoder
* GhosttyKeyEncoder encoder;
* GhosttyResult result = ghostty_key_encoder_new(NULL, &encoder);
* assert(result == GHOSTTY_SUCCESS);
*
* // Enable Kitty keyboard protocol with all features
* ghostty_key_encoder_setopt(encoder, GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS,
* &(uint8_t){GHOSTTY_KITTY_KEY_ALL});
*
* // Create and configure key event for Ctrl+C press
* GhosttyKeyEvent event;
* result = ghostty_key_event_new(NULL, &event);
* assert(result == GHOSTTY_SUCCESS);
* ghostty_key_event_set_action(event, GHOSTTY_KEY_ACTION_PRESS);
* ghostty_key_event_set_key(event, GHOSTTY_KEY_C);
* ghostty_key_event_set_mods(event, GHOSTTY_MODS_CTRL);
*
* // Encode the key event
* char buf[128];
* size_t written = 0;
* result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
* assert(result == GHOSTTY_SUCCESS);
*
* // Use the encoded sequence (e.g., write to terminal)
* fwrite(buf, 1, written, stdout);
*
* // Cleanup
* ghostty_key_event_free(event);
* ghostty_key_encoder_free(encoder);
* return 0;
* }
* @endcode
*
* For a complete working example, see example/c-vt-key-encode in the
* repository.
*
* @{
*/
#include <ghostty/vt/key/event.h>
#include <ghostty/vt/key/encoder.h>
/** @} */
#endif /* GHOSTTY_VT_KEY_H */

View File

@@ -0,0 +1,221 @@
/**
* @file encoder.h
*
* Key event encoding to terminal escape sequences.
*/
#ifndef GHOSTTY_VT_KEY_ENCODER_H
#define GHOSTTY_VT_KEY_ENCODER_H
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/result.h>
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/key/event.h>
/**
* Opaque handle to a key encoder instance.
*
* This handle represents a key encoder that converts key events into terminal
* escape sequences.
*
* @ingroup key
*/
typedef struct GhosttyKeyEncoder *GhosttyKeyEncoder;
/**
* Kitty keyboard protocol flags.
*
* Bitflags representing the various modes of the Kitty keyboard protocol.
* These can be combined using bitwise OR operations. Valid values all
* start with `GHOSTTY_KITTY_KEY_`.
*
* @ingroup key
*/
typedef uint8_t GhosttyKittyKeyFlags;
/** Kitty keyboard protocol disabled (all flags off) */
#define GHOSTTY_KITTY_KEY_DISABLED 0
/** Disambiguate escape codes */
#define GHOSTTY_KITTY_KEY_DISAMBIGUATE (1 << 0)
/** Report key press and release events */
#define GHOSTTY_KITTY_KEY_REPORT_EVENTS (1 << 1)
/** Report alternate key codes */
#define GHOSTTY_KITTY_KEY_REPORT_ALTERNATES (1 << 2)
/** Report all key events including those normally handled by the terminal */
#define GHOSTTY_KITTY_KEY_REPORT_ALL (1 << 3)
/** Report associated text with key events */
#define GHOSTTY_KITTY_KEY_REPORT_ASSOCIATED (1 << 4)
/** All Kitty keyboard protocol flags enabled */
#define GHOSTTY_KITTY_KEY_ALL (GHOSTTY_KITTY_KEY_DISAMBIGUATE | GHOSTTY_KITTY_KEY_REPORT_EVENTS | GHOSTTY_KITTY_KEY_REPORT_ALTERNATES | GHOSTTY_KITTY_KEY_REPORT_ALL | GHOSTTY_KITTY_KEY_REPORT_ASSOCIATED)
/**
* macOS option key behavior.
*
* Determines whether the "option" key on macOS is treated as "alt" or not.
* See the Ghostty `macos-option-as-alt` configuration option for more details.
*
* @ingroup key
*/
typedef enum {
/** Option key is not treated as alt */
GHOSTTY_OPTION_AS_ALT_FALSE = 0,
/** Option key is treated as alt */
GHOSTTY_OPTION_AS_ALT_TRUE = 1,
/** Only left option key is treated as alt */
GHOSTTY_OPTION_AS_ALT_LEFT = 2,
/** Only right option key is treated as alt */
GHOSTTY_OPTION_AS_ALT_RIGHT = 3,
} GhosttyOptionAsAlt;
/**
* Key encoder option identifiers.
*
* These values are used with ghostty_key_encoder_setopt() to configure
* the behavior of the key encoder.
*
* @ingroup key
*/
typedef enum {
/** Terminal DEC mode 1: cursor key application mode (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_CURSOR_KEY_APPLICATION = 0,
/** Terminal DEC mode 66: keypad key application mode (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_KEYPAD_KEY_APPLICATION = 1,
/** Terminal DEC mode 1035: ignore keypad with numlock (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_IGNORE_KEYPAD_WITH_NUMLOCK = 2,
/** Terminal DEC mode 1036: alt sends escape prefix (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_ALT_ESC_PREFIX = 3,
/** xterm modifyOtherKeys mode 2 (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_MODIFY_OTHER_KEYS_STATE_2 = 4,
/** Kitty keyboard protocol flags (value: GhosttyKittyKeyFlags bitmask) */
GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS = 5,
/** macOS option-as-alt setting (value: GhosttyOptionAsAlt) */
GHOSTTY_KEY_ENCODER_OPT_MACOS_OPTION_AS_ALT = 6,
} GhosttyKeyEncoderOption;
/**
* Create a new key encoder instance.
*
* Creates a new key encoder with default options. The encoder can be configured
* using ghostty_key_encoder_setopt() and must be freed using
* ghostty_key_encoder_free() when no longer needed.
*
* @param allocator Pointer to the allocator to use for memory management, or NULL to use the default allocator
* @param encoder Pointer to store the created encoder handle
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup key
*/
GhosttyResult ghostty_key_encoder_new(const GhosttyAllocator *allocator, GhosttyKeyEncoder *encoder);
/**
* Free a key encoder instance.
*
* Releases all resources associated with the key encoder. After this call,
* the encoder handle becomes invalid and must not be used.
*
* @param encoder The encoder handle to free (may be NULL)
*
* @ingroup key
*/
void ghostty_key_encoder_free(GhosttyKeyEncoder encoder);
/**
* Set an option on the key encoder.
*
* Configures the behavior of the key encoder. Options control various aspects
* of encoding such as terminal modes (cursor key application mode, keypad mode),
* protocol selection (Kitty keyboard protocol flags), and platform-specific
* behaviors (macOS option-as-alt).
*
* A null pointer value does nothing. It does not reset the value to the
* default. The setopt call will do nothing.
*
* @param encoder The encoder handle, must not be NULL
* @param option The option to set
* @param value Pointer to the value to set (type depends on the option)
*
* @ingroup key
*/
void ghostty_key_encoder_setopt(GhosttyKeyEncoder encoder, GhosttyKeyEncoderOption option, const void *value);
/**
* Encode a key event into a terminal escape sequence.
*
* Converts a key event into the appropriate terminal escape sequence based on
* the encoder's current options. The sequence is written to the provided buffer.
*
* Not all key events produce output. For example, unmodified modifier keys
* typically don't generate escape sequences. Check the out_len parameter to
* determine if any data was written.
*
* If the output buffer is too small, this function returns GHOSTTY_OUT_OF_MEMORY
* and out_len will contain the required buffer size. The caller can then
* allocate a larger buffer and call the function again.
*
* @param encoder The encoder handle, must not be NULL
* @param event The key event to encode, must not be NULL
* @param out_buf Buffer to write the encoded sequence to
* @param out_buf_size Size of the output buffer in bytes
* @param out_len Pointer to store the number of bytes written (may be NULL)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_MEMORY if buffer too small, or other error code
*
* ## Example: Calculate required buffer size
*
* @code{.c}
* // Query the required size with a NULL buffer (always returns OUT_OF_MEMORY)
* size_t required = 0;
* GhosttyResult result = ghostty_key_encoder_encode(encoder, event, NULL, 0, &required);
* assert(result == GHOSTTY_OUT_OF_MEMORY);
*
* // Allocate buffer of required size
* char *buf = malloc(required);
*
* // Encode with properly sized buffer
* size_t written = 0;
* result = ghostty_key_encoder_encode(encoder, event, buf, required, &written);
* assert(result == GHOSTTY_SUCCESS);
*
* // Use the encoded sequence...
*
* free(buf);
* @endcode
*
* ## Example: Direct encoding with static buffer
*
* @code{.c}
* // Most escape sequences are short, so a static buffer often suffices
* char buf[128];
* size_t written = 0;
* GhosttyResult result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
*
* if (result == GHOSTTY_SUCCESS) {
* // Write the encoded sequence to the terminal
* write(pty_fd, buf, written);
* } else if (result == GHOSTTY_OUT_OF_MEMORY) {
* // Buffer too small, written contains required size
* char *dynamic_buf = malloc(written);
* result = ghostty_key_encoder_encode(encoder, event, dynamic_buf, written, &written);
* assert(result == GHOSTTY_SUCCESS);
* write(pty_fd, dynamic_buf, written);
* free(dynamic_buf);
* }
* @endcode
*
* @ingroup key
*/
GhosttyResult ghostty_key_encoder_encode(GhosttyKeyEncoder encoder, GhosttyKeyEvent event, char *out_buf, size_t out_buf_size, size_t *out_len);
#endif /* GHOSTTY_VT_KEY_ENCODER_H */

View File

@@ -0,0 +1,474 @@
/**
* @file event.h
*
* Key event representation and manipulation.
*/
#ifndef GHOSTTY_VT_KEY_EVENT_H
#define GHOSTTY_VT_KEY_EVENT_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/result.h>
#include <ghostty/vt/allocator.h>
/**
* Opaque handle to a key event.
*
* This handle represents a keyboard input event containing information about
* the physical key pressed, modifiers, and generated text.
*
* @ingroup key
*/
typedef struct GhosttyKeyEvent *GhosttyKeyEvent;
/**
* Keyboard input event types.
*
* @ingroup key
*/
typedef enum {
/** Key was released */
GHOSTTY_KEY_ACTION_RELEASE = 0,
/** Key was pressed */
GHOSTTY_KEY_ACTION_PRESS = 1,
/** Key is being repeated (held down) */
GHOSTTY_KEY_ACTION_REPEAT = 2,
} GhosttyKeyAction;
/**
* Keyboard modifier keys bitmask.
*
* A bitmask representing all keyboard modifiers. This tracks which modifier keys
* are pressed and, where supported by the platform, which side (left or right)
* of each modifier is active.
*
* Use the GHOSTTY_MODS_* constants to test and set individual modifiers.
*
* Modifier side bits are only meaningful when the corresponding modifier bit is set.
* Not all platforms support distinguishing between left and right modifier
* keys and Ghostty is built to expect that some platforms may not provide this
* information.
*
* @ingroup key
*/
typedef uint16_t GhosttyMods;
/** Shift key is pressed */
#define GHOSTTY_MODS_SHIFT (1 << 0)
/** Control key is pressed */
#define GHOSTTY_MODS_CTRL (1 << 1)
/** Alt/Option key is pressed */
#define GHOSTTY_MODS_ALT (1 << 2)
/** Super/Command/Windows key is pressed */
#define GHOSTTY_MODS_SUPER (1 << 3)
/** Caps Lock is active */
#define GHOSTTY_MODS_CAPS_LOCK (1 << 4)
/** Num Lock is active */
#define GHOSTTY_MODS_NUM_LOCK (1 << 5)
/**
* Right shift is pressed (0 = left, 1 = right).
* Only meaningful when GHOSTTY_MODS_SHIFT is set.
*/
#define GHOSTTY_MODS_SHIFT_SIDE (1 << 6)
/**
* Right ctrl is pressed (0 = left, 1 = right).
* Only meaningful when GHOSTTY_MODS_CTRL is set.
*/
#define GHOSTTY_MODS_CTRL_SIDE (1 << 7)
/**
* Right alt is pressed (0 = left, 1 = right).
* Only meaningful when GHOSTTY_MODS_ALT is set.
*/
#define GHOSTTY_MODS_ALT_SIDE (1 << 8)
/**
* Right super is pressed (0 = left, 1 = right).
* Only meaningful when GHOSTTY_MODS_SUPER is set.
*/
#define GHOSTTY_MODS_SUPER_SIDE (1 << 9)
/**
* Physical key codes.
*
* The set of key codes that Ghostty is aware of. These represent physical keys
* on the keyboard and are layout-independent. For example, the "a" key on a US
* keyboard is the same as the "ф" key on a Russian keyboard, but both will
* report the same key_a value.
*
* Layout-dependent strings are provided separately as UTF-8 text and are produced
* by the platform. These values are based on the W3C UI Events KeyboardEvent code
* standard. See: https://www.w3.org/TR/uievents-code
*
* @ingroup key
*/
typedef enum {
GHOSTTY_KEY_UNIDENTIFIED = 0,
// Writing System Keys (W3C § 3.1.1)
GHOSTTY_KEY_BACKQUOTE,
GHOSTTY_KEY_BACKSLASH,
GHOSTTY_KEY_BRACKET_LEFT,
GHOSTTY_KEY_BRACKET_RIGHT,
GHOSTTY_KEY_COMMA,
GHOSTTY_KEY_DIGIT_0,
GHOSTTY_KEY_DIGIT_1,
GHOSTTY_KEY_DIGIT_2,
GHOSTTY_KEY_DIGIT_3,
GHOSTTY_KEY_DIGIT_4,
GHOSTTY_KEY_DIGIT_5,
GHOSTTY_KEY_DIGIT_6,
GHOSTTY_KEY_DIGIT_7,
GHOSTTY_KEY_DIGIT_8,
GHOSTTY_KEY_DIGIT_9,
GHOSTTY_KEY_EQUAL,
GHOSTTY_KEY_INTL_BACKSLASH,
GHOSTTY_KEY_INTL_RO,
GHOSTTY_KEY_INTL_YEN,
GHOSTTY_KEY_A,
GHOSTTY_KEY_B,
GHOSTTY_KEY_C,
GHOSTTY_KEY_D,
GHOSTTY_KEY_E,
GHOSTTY_KEY_F,
GHOSTTY_KEY_G,
GHOSTTY_KEY_H,
GHOSTTY_KEY_I,
GHOSTTY_KEY_J,
GHOSTTY_KEY_K,
GHOSTTY_KEY_L,
GHOSTTY_KEY_M,
GHOSTTY_KEY_N,
GHOSTTY_KEY_O,
GHOSTTY_KEY_P,
GHOSTTY_KEY_Q,
GHOSTTY_KEY_R,
GHOSTTY_KEY_S,
GHOSTTY_KEY_T,
GHOSTTY_KEY_U,
GHOSTTY_KEY_V,
GHOSTTY_KEY_W,
GHOSTTY_KEY_X,
GHOSTTY_KEY_Y,
GHOSTTY_KEY_Z,
GHOSTTY_KEY_MINUS,
GHOSTTY_KEY_PERIOD,
GHOSTTY_KEY_QUOTE,
GHOSTTY_KEY_SEMICOLON,
GHOSTTY_KEY_SLASH,
// Functional Keys (W3C § 3.1.2)
GHOSTTY_KEY_ALT_LEFT,
GHOSTTY_KEY_ALT_RIGHT,
GHOSTTY_KEY_BACKSPACE,
GHOSTTY_KEY_CAPS_LOCK,
GHOSTTY_KEY_CONTEXT_MENU,
GHOSTTY_KEY_CONTROL_LEFT,
GHOSTTY_KEY_CONTROL_RIGHT,
GHOSTTY_KEY_ENTER,
GHOSTTY_KEY_META_LEFT,
GHOSTTY_KEY_META_RIGHT,
GHOSTTY_KEY_SHIFT_LEFT,
GHOSTTY_KEY_SHIFT_RIGHT,
GHOSTTY_KEY_SPACE,
GHOSTTY_KEY_TAB,
GHOSTTY_KEY_CONVERT,
GHOSTTY_KEY_KANA_MODE,
GHOSTTY_KEY_NON_CONVERT,
// Control Pad Section (W3C § 3.2)
GHOSTTY_KEY_DELETE,
GHOSTTY_KEY_END,
GHOSTTY_KEY_HELP,
GHOSTTY_KEY_HOME,
GHOSTTY_KEY_INSERT,
GHOSTTY_KEY_PAGE_DOWN,
GHOSTTY_KEY_PAGE_UP,
// Arrow Pad Section (W3C § 3.3)
GHOSTTY_KEY_ARROW_DOWN,
GHOSTTY_KEY_ARROW_LEFT,
GHOSTTY_KEY_ARROW_RIGHT,
GHOSTTY_KEY_ARROW_UP,
// Numpad Section (W3C § 3.4)
GHOSTTY_KEY_NUM_LOCK,
GHOSTTY_KEY_NUMPAD_0,
GHOSTTY_KEY_NUMPAD_1,
GHOSTTY_KEY_NUMPAD_2,
GHOSTTY_KEY_NUMPAD_3,
GHOSTTY_KEY_NUMPAD_4,
GHOSTTY_KEY_NUMPAD_5,
GHOSTTY_KEY_NUMPAD_6,
GHOSTTY_KEY_NUMPAD_7,
GHOSTTY_KEY_NUMPAD_8,
GHOSTTY_KEY_NUMPAD_9,
GHOSTTY_KEY_NUMPAD_ADD,
GHOSTTY_KEY_NUMPAD_BACKSPACE,
GHOSTTY_KEY_NUMPAD_CLEAR,
GHOSTTY_KEY_NUMPAD_CLEAR_ENTRY,
GHOSTTY_KEY_NUMPAD_COMMA,
GHOSTTY_KEY_NUMPAD_DECIMAL,
GHOSTTY_KEY_NUMPAD_DIVIDE,
GHOSTTY_KEY_NUMPAD_ENTER,
GHOSTTY_KEY_NUMPAD_EQUAL,
GHOSTTY_KEY_NUMPAD_MEMORY_ADD,
GHOSTTY_KEY_NUMPAD_MEMORY_CLEAR,
GHOSTTY_KEY_NUMPAD_MEMORY_RECALL,
GHOSTTY_KEY_NUMPAD_MEMORY_STORE,
GHOSTTY_KEY_NUMPAD_MEMORY_SUBTRACT,
GHOSTTY_KEY_NUMPAD_MULTIPLY,
GHOSTTY_KEY_NUMPAD_PAREN_LEFT,
GHOSTTY_KEY_NUMPAD_PAREN_RIGHT,
GHOSTTY_KEY_NUMPAD_SUBTRACT,
GHOSTTY_KEY_NUMPAD_SEPARATOR,
GHOSTTY_KEY_NUMPAD_UP,
GHOSTTY_KEY_NUMPAD_DOWN,
GHOSTTY_KEY_NUMPAD_RIGHT,
GHOSTTY_KEY_NUMPAD_LEFT,
GHOSTTY_KEY_NUMPAD_BEGIN,
GHOSTTY_KEY_NUMPAD_HOME,
GHOSTTY_KEY_NUMPAD_END,
GHOSTTY_KEY_NUMPAD_INSERT,
GHOSTTY_KEY_NUMPAD_DELETE,
GHOSTTY_KEY_NUMPAD_PAGE_UP,
GHOSTTY_KEY_NUMPAD_PAGE_DOWN,
// Function Section (W3C § 3.5)
GHOSTTY_KEY_ESCAPE,
GHOSTTY_KEY_F1,
GHOSTTY_KEY_F2,
GHOSTTY_KEY_F3,
GHOSTTY_KEY_F4,
GHOSTTY_KEY_F5,
GHOSTTY_KEY_F6,
GHOSTTY_KEY_F7,
GHOSTTY_KEY_F8,
GHOSTTY_KEY_F9,
GHOSTTY_KEY_F10,
GHOSTTY_KEY_F11,
GHOSTTY_KEY_F12,
GHOSTTY_KEY_F13,
GHOSTTY_KEY_F14,
GHOSTTY_KEY_F15,
GHOSTTY_KEY_F16,
GHOSTTY_KEY_F17,
GHOSTTY_KEY_F18,
GHOSTTY_KEY_F19,
GHOSTTY_KEY_F20,
GHOSTTY_KEY_F21,
GHOSTTY_KEY_F22,
GHOSTTY_KEY_F23,
GHOSTTY_KEY_F24,
GHOSTTY_KEY_F25,
GHOSTTY_KEY_FN,
GHOSTTY_KEY_FN_LOCK,
GHOSTTY_KEY_PRINT_SCREEN,
GHOSTTY_KEY_SCROLL_LOCK,
GHOSTTY_KEY_PAUSE,
// Media Keys (W3C § 3.6)
GHOSTTY_KEY_BROWSER_BACK,
GHOSTTY_KEY_BROWSER_FAVORITES,
GHOSTTY_KEY_BROWSER_FORWARD,
GHOSTTY_KEY_BROWSER_HOME,
GHOSTTY_KEY_BROWSER_REFRESH,
GHOSTTY_KEY_BROWSER_SEARCH,
GHOSTTY_KEY_BROWSER_STOP,
GHOSTTY_KEY_EJECT,
GHOSTTY_KEY_LAUNCH_APP_1,
GHOSTTY_KEY_LAUNCH_APP_2,
GHOSTTY_KEY_LAUNCH_MAIL,
GHOSTTY_KEY_MEDIA_PLAY_PAUSE,
GHOSTTY_KEY_MEDIA_SELECT,
GHOSTTY_KEY_MEDIA_STOP,
GHOSTTY_KEY_MEDIA_TRACK_NEXT,
GHOSTTY_KEY_MEDIA_TRACK_PREVIOUS,
GHOSTTY_KEY_POWER,
GHOSTTY_KEY_SLEEP,
GHOSTTY_KEY_AUDIO_VOLUME_DOWN,
GHOSTTY_KEY_AUDIO_VOLUME_MUTE,
GHOSTTY_KEY_AUDIO_VOLUME_UP,
GHOSTTY_KEY_WAKE_UP,
// Legacy, Non-standard, and Special Keys (W3C § 3.7)
GHOSTTY_KEY_COPY,
GHOSTTY_KEY_CUT,
GHOSTTY_KEY_PASTE,
} GhosttyKey;
/**
* Create a new key event instance.
*
* Creates a new key event with default values. The event must be freed using
* ghostty_key_event_free() when no longer needed.
*
* @param allocator Pointer to the allocator to use for memory management, or NULL to use the default allocator
* @param event Pointer to store the created key event handle
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup key
*/
GhosttyResult ghostty_key_event_new(const GhosttyAllocator *allocator, GhosttyKeyEvent *event);
/**
* Free a key event instance.
*
* Releases all resources associated with the key event. After this call,
* the event handle becomes invalid and must not be used.
*
* @param event The key event handle to free (may be NULL)
*
* @ingroup key
*/
void ghostty_key_event_free(GhosttyKeyEvent event);
/**
* Set the key action (press, release, repeat).
*
* @param event The key event handle, must not be NULL
* @param action The action to set
*
* @ingroup key
*/
void ghostty_key_event_set_action(GhosttyKeyEvent event, GhosttyKeyAction action);
/**
* Get the key action (press, release, repeat).
*
* @param event The key event handle, must not be NULL
* @return The key action
*
* @ingroup key
*/
GhosttyKeyAction ghostty_key_event_get_action(GhosttyKeyEvent event);
/**
* Set the physical key code.
*
* @param event The key event handle, must not be NULL
* @param key The physical key code to set
*
* @ingroup key
*/
void ghostty_key_event_set_key(GhosttyKeyEvent event, GhosttyKey key);
/**
* Get the physical key code.
*
* @param event The key event handle, must not be NULL
* @return The physical key code
*
* @ingroup key
*/
GhosttyKey ghostty_key_event_get_key(GhosttyKeyEvent event);
/**
* Set the modifier keys bitmask.
*
* @param event The key event handle, must not be NULL
* @param mods The modifier keys bitmask to set
*
* @ingroup key
*/
void ghostty_key_event_set_mods(GhosttyKeyEvent event, GhosttyMods mods);
/**
* Get the modifier keys bitmask.
*
* @param event The key event handle, must not be NULL
* @return The modifier keys bitmask
*
* @ingroup key
*/
GhosttyMods ghostty_key_event_get_mods(GhosttyKeyEvent event);
/**
* Set the consumed modifiers bitmask.
*
* @param event The key event handle, must not be NULL
* @param consumed_mods The consumed modifiers bitmask to set
*
* @ingroup key
*/
void ghostty_key_event_set_consumed_mods(GhosttyKeyEvent event, GhosttyMods consumed_mods);
/**
* Get the consumed modifiers bitmask.
*
* @param event The key event handle, must not be NULL
* @return The consumed modifiers bitmask
*
* @ingroup key
*/
GhosttyMods ghostty_key_event_get_consumed_mods(GhosttyKeyEvent event);
/**
* Set whether the key event is part of a composition sequence.
*
* @param event The key event handle, must not be NULL
* @param composing Whether the key event is part of a composition sequence
*
* @ingroup key
*/
void ghostty_key_event_set_composing(GhosttyKeyEvent event, bool composing);
/**
* Get whether the key event is part of a composition sequence.
*
* @param event The key event handle, must not be NULL
* @return Whether the key event is part of a composition sequence
*
* @ingroup key
*/
bool ghostty_key_event_get_composing(GhosttyKeyEvent event);
/**
* Set the UTF-8 text generated by the key event.
*
* The key event does NOT take ownership of the text pointer. The caller
* must ensure the string remains valid for the lifetime needed by the event.
*
* @param event The key event handle, must not be NULL
* @param utf8 The UTF-8 text to set (or NULL for empty)
* @param len Length of the UTF-8 text in bytes
*
* @ingroup key
*/
void ghostty_key_event_set_utf8(GhosttyKeyEvent event, const char *utf8, size_t len);
/**
* Get the UTF-8 text generated by the key event.
*
* The returned pointer is valid until the event is freed or the UTF-8 text is modified.
*
* @param event The key event handle, must not be NULL
* @param len Pointer to store the length of the UTF-8 text in bytes (may be NULL)
* @return The UTF-8 text (or NULL for empty)
*
* @ingroup key
*/
const char *ghostty_key_event_get_utf8(GhosttyKeyEvent event, size_t *len);
/**
* Set the unshifted Unicode codepoint.
*
* @param event The key event handle, must not be NULL
* @param codepoint The unshifted Unicode codepoint to set
*
* @ingroup key
*/
void ghostty_key_event_set_unshifted_codepoint(GhosttyKeyEvent event, uint32_t codepoint);
/**
* Get the unshifted Unicode codepoint.
*
* @param event The key event handle, must not be NULL
* @return The unshifted Unicode codepoint
*
* @ingroup key
*/
uint32_t ghostty_key_event_get_unshifted_codepoint(GhosttyKeyEvent event);
#endif /* GHOSTTY_VT_KEY_EVENT_H */

231
include/ghostty/vt/osc.h Normal file
View File

@@ -0,0 +1,231 @@
/**
* @file osc.h
*
* OSC (Operating System Command) sequence parser and command handling.
*/
#ifndef GHOSTTY_VT_OSC_H
#define GHOSTTY_VT_OSC_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/result.h>
#include <ghostty/vt/allocator.h>
/**
* 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.
*
* @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.
*
* @ingroup osc
*/
typedef struct GhosttyOscCommand *GhosttyOscCommand;
/** @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
*
* @{
*/
/**
* 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;
/**
* 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
*
* @ingroup osc
*/
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)
*
* @ingroup osc
*/
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.
*
* @ingroup osc
*/
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
*
* @ingroup osc
*/
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
*
* @ingroup osc
*/
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
*
* @ingroup osc
*/
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
*
* @ingroup osc
*/
bool ghostty_osc_command_data(GhosttyOscCommand command, GhosttyOscCommandData data, void *out);
/** @} */
#endif /* GHOSTTY_VT_OSC_H */

View File

@@ -0,0 +1,75 @@
/**
* @file paste.h
*
* Paste utilities - validate and encode paste data for terminal input.
*/
#ifndef GHOSTTY_VT_PASTE_H
#define GHOSTTY_VT_PASTE_H
/** @defgroup paste Paste Utilities
*
* Utilities for validating paste data safety.
*
* ## Basic Usage
*
* Use ghostty_paste_is_safe() to check if paste data contains potentially
* dangerous sequences before sending it to the terminal.
*
* ## Example
*
* @code{.c}
* #include <stdio.h>
* #include <string.h>
* #include <ghostty/vt.h>
*
* int main() {
* const char* safe_data = "hello world";
* const char* unsafe_data = "rm -rf /\n";
*
* if (ghostty_paste_is_safe(safe_data, strlen(safe_data))) {
* printf("Safe to paste\n");
* }
*
* if (!ghostty_paste_is_safe(unsafe_data, strlen(unsafe_data))) {
* printf("Unsafe! Contains newline\n");
* }
*
* return 0;
* }
* @endcode
*
* @{
*/
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Check if paste data is safe to paste into the terminal.
*
* Data is considered unsafe if it contains:
* - Newlines (`\n`) which can inject commands
* - The bracketed paste end sequence (`\x1b[201~`) which can be used
* to exit bracketed paste mode and inject commands
*
* This check is conservative and considers data unsafe regardless of
* current terminal state.
*
* @param data The paste data to check (must not be NULL)
* @param len The length of the data in bytes
* @return true if the data is safe to paste, false otherwise
*/
bool ghostty_paste_is_safe(const char* data, size_t len);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* GHOSTTY_VT_PASTE_H */

View File

@@ -0,0 +1,20 @@
/**
* @file result.h
*
* Result codes for libghostty-vt operations.
*/
#ifndef GHOSTTY_VT_RESULT_H
#define GHOSTTY_VT_RESULT_H
/**
* 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;
#endif /* GHOSTTY_VT_RESULT_H */

View File

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

View File

@@ -860,7 +860,12 @@ class AppDelegate: NSObject,
} else {
GlobalEventTap.shared.disable()
}
}
/// Sync the appearance of our app with the theme specified in the config.
private func syncAppearance(config: Ghostty.Config) {
NSApplication.shared.appearance = .init(ghosttyConfig: config)
switch (config.macosIcon) {
case .official:
self.appIcon = nil
@@ -909,11 +914,6 @@ class AppDelegate: NSObject,
}
}
/// Sync the appearance of our app with the theme specified in the config.
private func syncAppearance(config: Ghostty.Config) {
NSApplication.shared.appearance = .init(ghosttyConfig: config)
}
//MARK: - Restorable State
/// We support NSSecureCoding for restorable state. Required as of macOS Sonoma (14) but a good idea anyways.

View File

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

View File

@@ -43,11 +43,13 @@ struct NewTerminalIntent: AppIntent {
)
var parent: TerminalEntity?
// Performing in the background can avoid opening multiple windows at the same time
// using `foreground` will cause `perform` and `AppDelegate.applicationDidBecomeActive(_:)`/`AppDelegate.applicationShouldHandleReopen(_:hasVisibleWindows:)` running at the 'same' time
@available(macOS 26.0, *)
static var supportedModes: IntentModes = .foreground(.immediate)
static var supportedModes: IntentModes = .background
@available(macOS, obsoleted: 26.0, message: "Replaced by supportedModes")
static var openAppWhenRun = true
static var openAppWhenRun = false
@MainActor
func perform() async throws -> some IntentResult & ReturnsValue<TerminalEntity?> {
@@ -96,6 +98,11 @@ struct NewTerminalIntent: AppIntent {
parent = nil
}
defer {
if !NSApp.isActive {
NSApp.activate(ignoringOtherApps: true)
}
}
switch location {
case .window:
let newController = TerminalController.newWindow(
@@ -123,7 +130,8 @@ struct NewTerminalIntent: AppIntent {
if let view = controller.newSplit(
at: parent,
direction: location.splitDirection!
direction: location.splitDirection!,
baseConfig: config
) {
return .result(value: TerminalEntity(view))
}

View File

@@ -21,13 +21,13 @@ class QuickTerminalController: BaseTerminalController {
// The active space when the quick terminal was last shown.
private var previousActiveSpace: CGSSpace? = nil
/// The window frame saved when the quick terminal's surface tree becomes empty.
/// The saved state when the quick terminal's surface tree becomes empty.
///
/// This preserves the user's window size and position when all terminal surfaces
/// are closed (e.g., via the `exit` command). When a new surface is created,
/// the window will be restored to this frame, preventing SwiftUI from resetting
/// the window to its default minimum size.
private var lastClosedFrame: NSRect? = nil
private var lastClosedFrames: NSMapTable<NSScreen, LastClosedState>
/// Non-nil if we have hidden dock state.
private var hiddenDock: HiddenDock? = nil
@@ -45,6 +45,10 @@ class QuickTerminalController: BaseTerminalController {
) {
self.position = position
self.derivedConfig = DerivedConfig(ghostty.config)
// This is a weak to strong mapping, so that our keys being NSScreens
// can remove themselves when they disappear.
self.lastClosedFrames = .weakToStrongObjects()
// Important detail here: we initialize with an empty surface tree so
// that we don't start a terminal process. This gets started when the
@@ -243,6 +247,22 @@ class QuickTerminalController: BaseTerminalController {
// MARK: Base Controller Overrides
override func focusSurface(_ view: Ghostty.SurfaceView) {
if visible {
// If we're visible, we just focus the surface as normal.
super.focusSurface(view)
return
}
// Check if target surface belongs to this quick terminal
guard surfaceTree.contains(view) else { return }
// Set the target surface as focused
DispatchQueue.main.async {
Ghostty.moveFocus(to: view)
}
// Animation completion handler will handle window/app activation
animateIn()
}
override func surfaceTreeDidChange(from: SplitTree<Ghostty.SurfaceView>, to: SplitTree<Ghostty.SurfaceView>) {
super.surfaceTreeDidChange(from: from, to: to)
@@ -360,8 +380,9 @@ class QuickTerminalController: BaseTerminalController {
guard let screen = derivedConfig.quickTerminalScreen.screen else { return }
// Grab our last closed frame to use, and clear our state since we're animating in.
let lastClosedFrame = self.lastClosedFrame
self.lastClosedFrame = nil
// We only use the last closed frame if we're opening on the same screen.
let lastClosedFrame: NSRect? = lastClosedFrames.object(forKey: screen)?.frame
lastClosedFrames.removeObject(forKey: screen)
// Move our window off screen to the initial animation position.
position.setInitial(
@@ -491,8 +512,8 @@ class QuickTerminalController: BaseTerminalController {
// the user's preferred window size and position for when the quick
// terminal is reactivated with a new surface. Without this, SwiftUI
// would reset the window to its minimum content size.
if window.frame.width > 0 && window.frame.height > 0 {
lastClosedFrame = window.frame
if window.frame.width > 0 && window.frame.height > 0, let screen = window.screen {
lastClosedFrames.setObject(.init(frame: window.frame), forKey: screen)
}
// If we hid the dock then we unhide it.
@@ -715,6 +736,14 @@ class QuickTerminalController: BaseTerminalController {
hidden = false
}
}
private class LastClosedState {
let frame: NSRect
init(frame: NSRect) {
self.frame = frame
}
}
}
extension Notification.Name {

View File

@@ -55,7 +55,10 @@ class ServiceProvider: NSObject {
_ = TerminalController.newWindow(delegate.ghostty, withBaseConfig: config)
case .tab:
_ = TerminalController.newTab(delegate.ghostty, withBaseConfig: config)
_ = TerminalController.newTab(
delegate.ghostty,
from: TerminalController.preferredParent?.window,
withBaseConfig: config)
}
}

View File

@@ -12,7 +12,7 @@ struct TerminalSplitTreeView: View {
onResize: onResize)
// This is necessary because we can't rely on SwiftUI's implicit
// structural identity to detect changes to this view. Due to
// the tree structure of splits it could result in bad beaviors.
// the tree structure of splits it could result in bad behaviors.
// See: https://github.com/ghostty-org/ghostty/issues/7546
.id(node.structuralIdentity)
}

View File

@@ -233,6 +233,21 @@ class BaseTerminalController: NSWindowController,
return newView
}
/// Move focus to a surface view.
func focusSurface(_ view: Ghostty.SurfaceView) {
// Check if target surface is in our tree
guard surfaceTree.contains(view) else { return }
// Move focus to the target surface and activate the window/app
DispatchQueue.main.async {
Ghostty.moveFocus(to: view)
view.window?.makeKeyAndOrderFront(nil)
if !NSApp.isActive {
NSApp.activate(ignoringOtherApps: true)
}
}
}
/// Called when the surfaceTree variable changed.
///
/// Subclasses should call super first.
@@ -688,6 +703,8 @@ class BaseTerminalController: NSWindowController,
surfaceTree.contains(titleSurface) {
// If we have a surface, we want to listen for title changes.
titleSurface.$title
.combineLatest(titleSurface.$bell)
.map { [weak self] in self?.computeTitle(title: $0, bell: $1) ?? "" }
.sink { [weak self] in self?.titleDidChange(to: $0) }
.store(in: &focusedSurfaceCancellables)
} else {
@@ -695,8 +712,17 @@ class BaseTerminalController: NSWindowController,
titleDidChange(to: "👻")
}
}
private func computeTitle(title: String, bell: Bool) -> String {
var result = title
if (bell && ghostty.config.bellFeatures.contains(.title)) {
result = "🔔 \(result)"
}
func titleDidChange(to: String) {
return result
}
private func titleDidChange(to: String) {
guard let window else { return }
// Set the main window title
@@ -717,6 +743,10 @@ class BaseTerminalController: NSWindowController,
func cellSizeDidChange(to: NSSize) {
guard derivedConfig.windowStepResize else { return }
// Stage manager can sometimes present windows in such a way that the
// cell size is temporarily zero due to the window being tiny. We can't
// set content resize increments to this value, so avoid an assertion failure.
guard to.width > 0 && to.height > 0 else { return }
self.window?.contentResizeIncrements = to
}
@@ -863,14 +893,6 @@ class BaseTerminalController: NSWindowController,
// Everything beyond here is setting up the window
guard let window else { return }
// If there is a hardcoded title in the configuration, we set that
// immediately. Future `set_title` apprt actions will override this
// if necessary but this ensures our window loads with the proper
// title immediately rather than on another event loop tick (see #5934)
if let title = derivedConfig.title {
window.title = title
}
// We always initialize our fullscreen style to native if we can because
// initialization sets up some state (i.e. observers). If its set already
// somehow we don't do this.
@@ -1072,20 +1094,17 @@ class BaseTerminalController: NSWindowController,
}
private struct DerivedConfig {
let title: String?
let macosTitlebarProxyIcon: Ghostty.MacOSTitlebarProxyIcon
let windowStepResize: Bool
let focusFollowsMouse: Bool
init() {
self.title = nil
self.macosTitlebarProxyIcon = .visible
self.windowStepResize = false
self.focusFollowsMouse = false
}
init(_ config: Ghostty.Config) {
self.title = config.title
self.macosTitlebarProxyIcon = config.macosTitlebarProxyIcon
self.windowStepResize = config.windowStepResize
self.focusFollowsMouse = config.focusFollowsMouse

View File

@@ -184,8 +184,14 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
static var preferredParent: TerminalController? {
all.first {
$0.window?.isMainWindow ?? false
} ?? all.last
} ?? lastMain ?? all.last
}
// The last controller to be main. We use this when paired with "preferredParent"
// to find the preferred window to attach new tabs, perform actions, etc. We
// always prefer the main window but if there isn't any (because we're triggered
// by something like an App Intent) then we prefer the most previous main.
static private(set) weak var lastMain: TerminalController? = nil
/// The "new window" action.
static func newWindow(
@@ -1036,6 +1042,9 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
if let window {
LastWindowPosition.shared.save(window)
}
// Remember our last main
Self.lastMain = self
}
// Called when the window will be encoded. We handle the data encoding here in the

View File

@@ -49,6 +49,14 @@ class TerminalWindow: NSWindow {
// Setup our initial config
derivedConfig = .init(config)
// If there is a hardcoded title in the configuration, we set that
// immediately. Future `set_title` apprt actions will override this
// if necessary but this ensures our window loads with the proper
// title immediately rather than on another event loop tick (see #5934)
if let title = derivedConfig.title {
self.title = title
}
// If window decorations are disabled, remove our title
if (!config.windowDecorations) { styleMask.remove(.titled) }
@@ -408,11 +416,19 @@ class TerminalWindow: NSWindow {
return
}
// Orient based on the top left of the primary monitor
let frame = screen.visibleFrame
setFrameOrigin(.init(
x: frame.minX + CGFloat(x),
y: frame.maxY - (CGFloat(y) + frame.height)))
// Convert top-left coordinates to bottom-left origin using our utility extension
let origin = screen.origin(
fromTopLeftOffsetX: CGFloat(x),
offsetY: CGFloat(y),
windowSize: frame.size)
// Clamp the origin to ensure the window stays fully visible on screen
var safeOrigin = origin
let vf = screen.visibleFrame
safeOrigin.x = min(max(safeOrigin.x, vf.minX), vf.maxX - frame.width)
safeOrigin.y = min(max(safeOrigin.y, vf.minY), vf.maxY - frame.height)
setFrameOrigin(safeOrigin)
}
private func hideWindowButtons() {
@@ -424,17 +440,20 @@ class TerminalWindow: NSWindow {
// MARK: Config
struct DerivedConfig {
let title: String?
let backgroundColor: NSColor
let backgroundOpacity: Double
let macosWindowButtons: Ghostty.MacOSWindowButtons
init() {
self.title = nil
self.backgroundColor = NSColor.windowBackgroundColor
self.backgroundOpacity = 1
self.macosWindowButtons = .visible
}
init(_ config: Ghostty.Config) {
self.title = config.title
self.backgroundColor = NSColor(config.backgroundColor)
self.backgroundOpacity = config.backgroundOpacity
self.macosWindowButtons = config.macosWindowButtons

View File

@@ -99,10 +99,13 @@ extension Ghostty.Action {
let state: State
let progress: UInt8?
init(c: ghostty_action_progress_report_s) {
self.state = State(c.state)
self.progress = c.progress >= 0 ? UInt8(c.progress) : nil
}
}
}
// Putting the initializer in an extension preserves the automatic one.
extension Ghostty.Action.ProgressReport {
init(c: ghostty_action_progress_report_s) {
self.state = State(c.state)
self.progress = c.progress >= 0 ? UInt8(c.progress) : nil
}
}

View File

@@ -624,10 +624,15 @@ extension Ghostty {
) -> Bool {
let action = Ghostty.Action.OpenURL(c: v)
// Convert the URL string to a URL object
guard let url = URL(string: action.url) else {
Ghostty.logger.warning("invalid URL for open URL action: \(action.url)")
return false
// If the URL doesn't have a valid scheme we assume its a file path. The URL
// initializer will gladly take invalid URLs (e.g. plain file paths) and turn
// them into schema-less URLs, but these won't open properly in text editors.
// See: https://github.com/ghostty-org/ghostty/issues/8763
let url: URL
if let candidate = URL(string: action.url), candidate.scheme != nil {
url = candidate
} else {
url = URL(filePath: action.url)
}
switch action.kind {

View File

@@ -314,17 +314,14 @@ extension Ghostty {
var macosCustomIcon: String {
#if os(macOS)
let homeDirURL = FileManager.default.homeDirectoryForCurrentUser
let ghosttyConfigIconPath = homeDirURL.appendingPathComponent(
".config/ghostty/Ghostty.icns",
conformingTo: .fileURL).path()
let defaultValue = ghosttyConfigIconPath
let defaultValue = NSString("~/.config/ghostty/Ghostty.icns").expandingTildeInPath
guard let config = self.config else { return defaultValue }
var v: UnsafePointer<Int8>? = nil
let key = "macos-custom-icon"
guard ghostty_config_get(config, &v, key, UInt(key.count)) else { return defaultValue }
guard let ptr = v else { return defaultValue }
return String(cString: ptr)
guard let path = NSString(utf8String: ptr) else { return defaultValue }
return path.expandingTildeInPath
#else
return ""
#endif
@@ -625,6 +622,7 @@ extension Ghostty.Config {
static let audio = BellFeatures(rawValue: 1 << 1)
static let attention = BellFeatures(rawValue: 1 << 2)
static let title = BellFeatures(rawValue: 1 << 3)
static let border = BellFeatures(rawValue: 1 << 4)
}
enum MacDockDropBehavior: String {

View File

@@ -0,0 +1,113 @@
import SwiftUI
/// The progress bar to show a surface progress report. We implement this from scratch because the
/// standard ProgressView is broken on macOS 26 and this is simple anyways and gives us a ton of
/// control.
struct SurfaceProgressBar: View {
let report: Ghostty.Action.ProgressReport
private var color: Color {
switch report.state {
case .error: return .red
case .pause: return .orange
default: return .accentColor
}
}
private var progress: UInt8? {
// If we have an explicit progress use that.
if let v = report.progress { return v }
// Otherwise, if we're in the pause state, we act as if we're at 100%.
if report.state == .pause { return 100 }
return nil
}
private var accessibilityLabel: String {
switch report.state {
case .error: return "Terminal progress - Error"
case .pause: return "Terminal progress - Paused"
case .indeterminate: return "Terminal progress - In progress"
default: return "Terminal progress"
}
}
private var accessibilityValue: String {
if let progress {
return "\(progress) percent complete"
} else {
switch report.state {
case .error: return "Operation failed"
case .pause: return "Operation paused at completion"
case .indeterminate: return "Operation in progress"
default: return "Indeterminate progress"
}
}
}
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .leading) {
if let progress {
// Determinate progress bar with specific percentage
Rectangle()
.fill(color)
.frame(
width: geometry.size.width * CGFloat(progress) / 100,
height: geometry.size.height
)
.animation(.easeInOut(duration: 0.2), value: progress)
} else {
// Indeterminate states without specific progress - all use bouncing animation
BouncingProgressBar(color: color)
}
}
}
.frame(height: 2)
.clipped()
.allowsHitTesting(false)
.accessibilityElement(children: .ignore)
.accessibilityAddTraits(.updatesFrequently)
.accessibilityLabel(accessibilityLabel)
.accessibilityValue(accessibilityValue)
}
}
/// Bouncing progress bar for indeterminate states
private struct BouncingProgressBar: View {
let color: Color
@State private var position: CGFloat = 0
private let barWidthRatio: CGFloat = 0.25
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .leading) {
Rectangle()
.fill(color.opacity(0.3))
Rectangle()
.fill(color)
.frame(
width: geometry.size.width * barWidthRatio,
height: geometry.size.height
)
.offset(x: position * (geometry.size.width * (1 - barWidthRatio)))
}
}
.onAppear {
withAnimation(
.easeInOut(duration: 1.2)
.repeatForever(autoreverses: true)
) {
position = 1
}
}
.onDisappear {
position = 0
}
}
}

View File

@@ -57,15 +57,6 @@ extension Ghostty {
@EnvironmentObject private var ghostty: Ghostty.App
var title: String {
var result = surfaceView.title
if (surfaceView.bell && ghostty.config.bellFeatures.contains(.title)) {
result = "🔔 \(result)"
}
return result
}
var body: some View {
let center = NotificationCenter.default
@@ -114,11 +105,17 @@ extension Ghostty {
}
.ghosttySurfaceView(surfaceView)
// Progress report overlay
if let progressReport = surfaceView.progressReport {
ProgressReportOverlay(report: progressReport)
// Progress report
if let progressReport = surfaceView.progressReport, progressReport.state != .remove {
VStack(spacing: 0) {
SurfaceProgressBar(report: progressReport)
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.allowsHitTesting(false)
.transition(.opacity)
}
#if canImport(AppKit)
// If we are in the middle of a key sequence, then we show a visual element. We only
// support this on macOS currently although in theory we can support mobile with keyboards!
@@ -201,6 +198,11 @@ extension Ghostty {
SecureInputOverlay()
}
#endif
// Show bell border if enabled
if (ghostty.config.bellFeatures.contains(.border)) {
BellBorderOverlay(bell: surfaceView.bell)
}
// If our surface is not healthy, then we render an error view over it.
if (!surfaceView.healthy) {
@@ -272,48 +274,7 @@ extension Ghostty {
}
}
// Progress report overlay that shows a progress bar at the top of the terminal
struct ProgressReportOverlay: View {
let report: Action.ProgressReport
@ViewBuilder
private var progressBar: some View {
if let progress = report.progress {
// Determinate progress bar
ProgressView(value: Double(progress), total: 100)
.progressViewStyle(.linear)
.tint(report.state == .error ? .red : report.state == .pause ? .orange : nil)
.animation(.easeInOut(duration: 0.2), value: progress)
} else {
// Indeterminate states
switch report.state {
case .indeterminate:
ProgressView()
.progressViewStyle(.linear)
case .error:
ProgressView()
.progressViewStyle(.linear)
.tint(.red)
case .pause:
Rectangle().fill(Color.orange)
default:
EmptyView()
}
}
}
var body: some View {
VStack(spacing: 0) {
progressBar
.scaleEffect(x: 1, y: 0.5, anchor: .center)
.frame(height: 2)
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.allowsHitTesting(false)
}
}
// This is the resize overlay that shows on top of a surface to show the current
// size during a resize operation.
@@ -570,6 +531,22 @@ extension Ghostty {
}
}
/// Visual overlay that shows a border around the edges when the bell rings with border feature enabled.
struct BellBorderOverlay: View {
let bell: Bool
var body: some View {
Rectangle()
.strokeBorder(
Color(red: 1.0, green: 0.8, blue: 0.0).opacity(0.5),
lineWidth: 3
)
.allowsHitTesting(false)
.opacity(bell ? 1.0 : 0.0)
.animation(.easeInOut(duration: 0.3), value: bell)
}
}
#if canImport(AppKit)
/// When changing the split state, or going full screen (native or non), the terminal view
/// will lose focus. There has to be some nice SwiftUI-native way to fix this but I can't

View File

@@ -1027,7 +1027,7 @@ extension Ghostty {
// If we are in a keyDown then we don't need to redispatch a command-modded
// key event (see docs for this field) so reset this to nil because
// `interpretKeyEvents` may dispach it.
// `interpretKeyEvents` may dispatch it.
self.lastPerformKeyEvent = nil
self.interpretKeyEvents([translationEvent])
@@ -1815,18 +1815,39 @@ extension Ghostty.SurfaceView: NSServicesMenuRequestor {
forSendType sendType: NSPasteboard.PasteboardType?,
returnType: NSPasteboard.PasteboardType?
) -> Any? {
// Types that we accept sent to us
let accepted: [NSPasteboard.PasteboardType] = [.string, .init("public.utf8-plain-text")]
// This function confused me a bit so I'm going to add my own commentary on
// how this works. macOS sends this callback with the given send/return types and
// we must return the responder capable of handling the COMBINATION of those send
// and return types (or super up if we can't handle it).
//
// The "COMBINATION" bit is key: we might get sent a string (we can handle that)
// but get requested an image (we can't handle that at the time of writing this),
// so we must bubble up.
// Types we can receive
let receivable: [NSPasteboard.PasteboardType] = [.string, .init("public.utf8-plain-text")]
// Types that we can send. Currently the same as receivable but I'm separating
// this out so we can modify this in the future.
let sendable: [NSPasteboard.PasteboardType] = receivable
// The sendable types that require a selection (currently all)
let sendableRequiresSelection = sendable
// We can always receive the accepted types
if (returnType == nil || accepted.contains(returnType!)) {
return self
}
// If we have a selection we can send the accepted types too
if ((self.surface != nil && ghostty_surface_has_selection(self.surface)) &&
(sendType == nil || accepted.contains(sendType!))
) {
// If we expect no data to be sent/received we can obviously handle it (that's
// the nil check), otherwise it must conform to the types we support on both sides.
if (returnType == nil || receivable.contains(returnType!)) &&
(sendType == nil || sendable.contains(sendType!)) {
// If we're expected to send back a type that requires selection, then
// verify that we have a selection. We do this within this block because
// validateRequestor is called a LOT and we want to prevent unnecessary
// performance hits because `ghostty_surface_has_selection` isn't free.
if let sendType, sendableRequiresSelection.contains(sendType) {
if surface == nil || !ghostty_surface_has_selection(surface) {
return super.validRequestor(forSendType: sendType, returnType: returnType)
}
}
return self
}

View File

@@ -41,4 +41,20 @@ extension NSScreen {
// know any other situation this is true.
return safeAreaInsets.top > 0
}
/// Converts top-left offset coordinates to bottom-left origin coordinates for window positioning.
/// - Parameters:
/// - x: X offset from top-left corner
/// - y: Y offset from top-left corner
/// - windowSize: Size of the window to be positioned
/// - Returns: CGPoint suitable for setFrameOrigin that positions the window as requested
func origin(fromTopLeftOffsetX x: CGFloat, offsetY y: CGFloat, windowSize: CGSize) -> CGPoint {
let vf = visibleFrame
// Convert top-left coordinates to bottom-left origin
let originX = vf.minX + x
let originY = vf.maxY - y - windowSize.height
return CGPoint(x: originX, y: originY)
}
}

View File

@@ -0,0 +1,99 @@
//
// WindowPositionTests.swift
// GhosttyTests
//
// Tests for window positioning coordinate conversion functionality.
//
import Testing
import AppKit
@testable import Ghostty
struct NSScreenExtensionTests {
/// Test positive coordinate conversion from top-left to bottom-left
@Test func testPositiveCoordinateConversion() async throws {
// Mock screen with 1000x800 visible frame starting at (0, 100)
let mockScreenFrame = NSRect(x: 0, y: 100, width: 1000, height: 800)
let mockScreen = MockNSScreen(visibleFrame: mockScreenFrame)
// Mock window size
let windowSize = CGSize(width: 400, height: 300)
// Test top-left positioning: x=15, y=15
let origin = mockScreen.origin(
fromTopLeftOffsetX: 15,
offsetY: 15,
windowSize: windowSize)
// Expected: x = 0 + 15 = 15, y = (100 + 800) - 15 - 300 = 585
#expect(origin.x == 15)
#expect(origin.y == 585)
}
/// Test zero coordinates (exact top-left corner)
@Test func testZeroCoordinates() async throws {
let mockScreenFrame = NSRect(x: 0, y: 100, width: 1000, height: 800)
let mockScreen = MockNSScreen(visibleFrame: mockScreenFrame)
let windowSize = CGSize(width: 400, height: 300)
let origin = mockScreen.origin(
fromTopLeftOffsetX: 0,
offsetY: 0,
windowSize: windowSize)
// Expected: x = 0, y = (100 + 800) - 0 - 300 = 600
#expect(origin.x == 0)
#expect(origin.y == 600)
}
/// Test with offset screen (not starting at origin)
@Test func testOffsetScreen() async throws {
// Secondary monitor at position (1440, 0) with 1920x1080 resolution
let mockScreenFrame = NSRect(x: 1440, y: 0, width: 1920, height: 1080)
let mockScreen = MockNSScreen(visibleFrame: mockScreenFrame)
let windowSize = CGSize(width: 600, height: 400)
let origin = mockScreen.origin(
fromTopLeftOffsetX: 100,
offsetY: 50,
windowSize: windowSize)
// Expected: x = 1440 + 100 = 1540, y = (0 + 1080) - 50 - 400 = 630
#expect(origin.x == 1540)
#expect(origin.y == 630)
}
/// Test large coordinates
@Test func testLargeCoordinates() async throws {
let mockScreenFrame = NSRect(x: 0, y: 0, width: 1920, height: 1080)
let mockScreen = MockNSScreen(visibleFrame: mockScreenFrame)
let windowSize = CGSize(width: 400, height: 300)
let origin = mockScreen.origin(
fromTopLeftOffsetX: 500,
offsetY: 200,
windowSize: windowSize)
// Expected: x = 0 + 500 = 500, y = (0 + 1080) - 200 - 300 = 580
#expect(origin.x == 500)
#expect(origin.y == 580)
}
}
/// Mock NSScreen class for testing coordinate conversion
private class MockNSScreen: NSScreen {
private let mockVisibleFrame: NSRect
init(visibleFrame: NSRect) {
self.mockVisibleFrame = visibleFrame
super.init()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var visibleFrame: NSRect {
return mockVisibleFrame
}
}

View File

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

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env nu
# This script downloads external dependencies from build.zig.zon.json that
# are not already mirrored at deps.files.ghostty.org, saves them to a local
# directory, and updates build.zig.zon to point to the new mirror URLs.
#
# The downloaded files are unmodified so their checksums and content hashes
# will match the originals.
#
# After running this script, the files in the output directory can be uploaded
# to blob storage, and build.zig.zon will already be updated with the new URLs.
def main [
--output: string = "tmp-mirror", # Output directory for the mirrored files
--prefix: string = "https://deps.files.ghostty.org/", # Final URL prefix to ignore
--dry-run, # Print what would be downloaded without downloading
] {
let script_dir = ($env.CURRENT_FILE | path dirname)
let input_file = ($script_dir | path join ".." ".." "build.zig.zon.json")
let zon_file = ($script_dir | path join ".." ".." "build.zig.zon")
let output_dir = $output
# Ensure the output directory exists
mkdir $output_dir
# Read and parse the JSON file
let deps = open $input_file
# Track URL replacements for build.zig.zon
mut url_replacements = []
# Process each dependency
for entry in ($deps | transpose key value) {
let key = $entry.key
let name = $entry.value.name
let url = $entry.value.url
# Skip URLs that don't start with http(s)
if not ($url | str starts-with "http") {
continue
}
# Skip URLs already hosted at the prefix
if ($url | str starts-with $prefix) {
continue
}
# Extract the file extension from the URL
let extension = ($url | parse -r '(\.[a-z0-9]+(?:\.[a-z0-9]+)?)$' | get -o capture0.0 | default "")
# Try to extract commit hash (40 hex chars) from URL
let commit_hash = ($url | parse -r '([a-f0-9]{40})' | get -o capture0.0 | default "")
# Try to extract date pattern (YYYY-MM-DD or YYYYMMDD with optional suffixes)
let date_pattern = ($url | parse -r '((?:release-)?20\d{2}(?:-?\d{2}){2}(?:[-]\d+)*(?:[-][a-z0-9]+)?)' | get -o capture0.0 | default "")
# Build filename based on what we found
let filename = if (not ($commit_hash | is-empty)) {
$"($name)-($commit_hash)($extension)"
} else if (not ($date_pattern | is-empty)) {
$"($name)-($date_pattern)($extension)"
} else {
$"($key)($extension)"
}
let new_url = $"($prefix)($filename)"
print $"($url) -> ($filename)"
# Track the replacement
$url_replacements = ($url_replacements | append {old: $url, new: $new_url})
# Download the file
if not $dry_run {
http get $url | save -f ($output_dir | path join $filename)
}
}
if $dry_run {
print "Dry run complete - no files were downloaded\n"
print $"Would update ($url_replacements | length) URLs in build.zig.zon"
} else {
print "All dependencies downloaded successfully\n"
print $"Updating ($zon_file)..."
# Backup the old file
let backup_file = $"($zon_file).bak"
cp $zon_file $backup_file
print $"Backed up to ($backup_file)"
mut zon_content = (open $zon_file)
for replacement in $url_replacements {
$zon_content = ($zon_content | str replace $replacement.old $replacement.new)
}
$zon_content | save -f $zon_file
print $"Updated ($url_replacements | length) URLs in build.zig.zon"
}
}

View File

@@ -1,30 +0,0 @@
#!/bin/sh
#
# This script generates a directory that can be uploaded to blob
# storage to mirror our dependencies. The dependencies are unmodified
# so their checksum and content hashes will match.
set -e # Exit immediately if a command exits with a non-zero status
SCRIPT_PATH="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)"
INPUT_FILE="$SCRIPT_PATH/../../build.zig.zon2json-lock"
OUTPUT_DIR="blob"
# Ensure the output directory exists
mkdir -p "$OUTPUT_DIR"
# Use jq to iterate over the JSON and download files
jq -r 'to_entries[] | "\(.key) \(.value.name) \(.value.url)"' "$INPUT_FILE" | while read -r key name url; do
# Skip URLs that don't start with http(s). They aren't necessary for
# our mirror.
if ! echo "$url" | grep -Eq "^https?://"; then
continue
fi
# Extract the file extension from the URL
extension=$(echo "$url" | grep -oE '\.[a-z0-9]+(\.[a-z0-9]+)?$')
filename="${name}-${key}${extension}"
echo "$url -> $filename"
curl -L -o "$OUTPUT_DIR/$filename" "$url"
done

View File

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

View File

@@ -10,7 +10,7 @@
git,
ncurses,
pkg-config,
zig_0_14,
zig_0_15,
pandoc,
revision ? "dirty",
optimize ? "Debug",
@@ -27,7 +27,7 @@
# https://github.com/ziglang/zig/issues/14281#issuecomment-1624220653 is
# ultimately acted on and has made its way to a nixpkgs implementation, this
# can probably be removed in favor of that.
zig_hook = zig_0_14.hook.overrideAttrs {
zig_hook = zig_0_15.hook.overrideAttrs {
zig_default_flags = "-Dcpu=baseline -Doptimize=${optimize} --color off";
};
gi_typelib_path = import ./build-support/gi-typelib-path.nix {
@@ -40,7 +40,7 @@
in
stdenv.mkDerivation (finalAttrs: {
pname = "ghostty";
version = "1.2.0";
version = "1.2.1";
# We limit source like this to try and reduce the amount of rebuilds as possible
# thus we only provide the source that is needed for the build

View File

@@ -46,19 +46,19 @@ pub fn addPaths(
// find the SDK path.
const libc = try std.zig.LibCInstallation.findNative(.{
.allocator = b.allocator,
.target = step.rootModuleTarget(),
.target = &step.rootModuleTarget(),
.verbose = false,
});
// Render the file compatible with the `--libc` Zig flag.
var list: std.ArrayList(u8) = .init(b.allocator);
defer list.deinit();
try libc.render(list.writer());
var stream: std.io.Writer.Allocating = .init(b.allocator);
defer stream.deinit();
try libc.render(&stream.writer);
// Create a temporary file to store the libc path because
// `--libc` expects a file path.
const wf = b.addWriteFiles();
const path = wf.add("libc.txt", list.items);
const path = wf.add("libc.txt", stream.written());
// Determine our framework path. Zig has a bug where it doesn't
// parse this from the libc txt file for `-framework` flags:

View File

@@ -19,9 +19,8 @@ pub fn build(b: *std.Build) !void {
try apple_sdk.addPaths(b, lib);
}
var flags = std.ArrayList([]const u8).init(b.allocator);
defer flags.deinit();
try flags.appendSlice(&.{});
var flags: std.ArrayList([]const u8) = .empty;
defer flags.deinit(b.allocator);
if (b.lazyDependency("breakpad", .{})) |upstream| {
lib.addIncludePath(upstream.path("src"));

View File

@@ -11,7 +11,7 @@ pub fn build(b: *std.Build) !void {
.optimize = optimize,
});
const imgui = b.dependency("imgui", .{});
const imgui_ = b.lazyDependency("imgui", .{});
const lib = b.addLibrary(.{
.name = "cimgui",
.root_module = b.createModule(.{
@@ -52,52 +52,53 @@ pub fn build(b: *std.Build) !void {
}
}
lib.addIncludePath(imgui.path(""));
if (imgui_) |imgui| lib.addIncludePath(imgui.path(""));
module.addIncludePath(b.path("vendor"));
var flags = std.ArrayList([]const u8).init(b.allocator);
defer flags.deinit();
try flags.appendSlice(&.{
var flags: std.ArrayList([]const u8) = .empty;
defer flags.deinit(b.allocator);
try flags.appendSlice(b.allocator, &.{
"-DCIMGUI_FREETYPE=1",
"-DIMGUI_USE_WCHAR32=1",
"-DIMGUI_DISABLE_OBSOLETE_FUNCTIONS=1",
});
if (target.result.os.tag == .windows) {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DIMGUI_IMPL_API=extern\t\"C\"\t__declspec(dllexport)",
});
} else {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DIMGUI_IMPL_API=extern\t\"C\"",
});
}
lib.addCSourceFile(.{ .file = b.path("vendor/cimgui.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_draw.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_demo.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_widgets.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_tables.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("misc/freetype/imgui_freetype.cpp"), .flags = flags.items });
lib.addCSourceFile(.{
.file = imgui.path("backends/imgui_impl_opengl3.cpp"),
.flags = flags.items,
});
if (target.result.os.tag.isDarwin()) {
if (!target.query.isNative()) {
try @import("apple_sdk").addPaths(b, lib);
}
if (imgui_) |imgui| {
lib.addCSourceFile(.{ .file = b.path("vendor/cimgui.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_draw.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_demo.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_widgets.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("imgui_tables.cpp"), .flags = flags.items });
lib.addCSourceFile(.{ .file = imgui.path("misc/freetype/imgui_freetype.cpp"), .flags = flags.items });
lib.addCSourceFile(.{
.file = imgui.path("backends/imgui_impl_metal.mm"),
.file = imgui.path("backends/imgui_impl_opengl3.cpp"),
.flags = flags.items,
});
if (target.result.os.tag == .macos) {
if (target.result.os.tag.isDarwin()) {
if (!target.query.isNative()) {
try @import("apple_sdk").addPaths(b, lib);
}
lib.addCSourceFile(.{
.file = imgui.path("backends/imgui_impl_osx.mm"),
.file = imgui.path("backends/imgui_impl_metal.mm"),
.flags = flags.items,
});
if (target.result.os.tag == .macos) {
lib.addCSourceFile(.{
.file = imgui.path("backends/imgui_impl_osx.mm"),
.flags = flags.items,
});
}
}
}

View File

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

View File

@@ -82,9 +82,9 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
lib.addIncludePath(b.path("override/include"));
module.addIncludePath(b.path("override/include"));
var flags = std.ArrayList([]const u8).init(b.allocator);
defer flags.deinit();
try flags.appendSlice(&.{
var flags: std.ArrayList([]const u8) = .empty;
defer flags.deinit(b.allocator);
try flags.appendSlice(b.allocator, &.{
"-DHAVE_DIRENT_H",
"-DHAVE_FCNTL_H",
"-DHAVE_STDLIB_H",
@@ -129,12 +129,12 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
});
switch (target.result.ptrBitWidth()) {
32 => try flags.appendSlice(&.{
32 => try flags.appendSlice(b.allocator, &.{
"-DSIZEOF_VOID_P=4",
"-DALIGNOF_VOID_P=4",
}),
64 => try flags.appendSlice(&.{
64 => try flags.appendSlice(b.allocator, &.{
"-DSIZEOF_VOID_P=8",
"-DALIGNOF_VOID_P=8",
}),
@@ -142,14 +142,14 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
else => @panic("unsupported arch"),
}
if (target.result.os.tag == .windows) {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DFC_CACHEDIR=\"LOCAL_APPDATA_FONTCONFIG_CACHE\"",
"-DFC_TEMPLATEDIR=\"c:/share/fontconfig/conf.avail\"",
"-DCONFIGDIR=\"c:/etc/fonts/conf.d\"",
"-DFC_DEFAULT_FONTS=\"\\t<dir>WINDOWSFONTDIR</dir>\\n\\t<dir>WINDOWSUSERFONTDIR</dir>\\n\"",
});
} else {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DHAVE_FSTATFS",
"-DHAVE_FSTATVFS",
"-DHAVE_GETOPT",
@@ -173,13 +173,13 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
});
if (target.result.os.tag == .freebsd) {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DFC_TEMPLATEDIR=\"/usr/local/etc/fonts/conf.avail\"",
"-DFONTCONFIG_PATH=\"/usr/local/etc/fonts\"",
"-DCONFIGDIR=\"/usr/local/etc/fonts/conf.d\"",
});
} else {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DFC_TEMPLATEDIR=\"/usr/share/fontconfig/conf.avail\"",
"-DFONTCONFIG_PATH=\"/etc/fonts\"",
"-DCONFIGDIR=\"/usr/local/fontconfig/conf.d\"",
@@ -187,7 +187,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
}
if (target.result.os.tag == .linux) {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DHAVE_SYS_STATFS_H",
"-DHAVE_SYS_VFS_H",
});
@@ -214,14 +214,14 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
// Libxml2
_ = b.systemIntegrationOption("libxml2", .{}); // So it shows up in help
if (libxml2_enabled) {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DENABLE_LIBXML2",
"-DLIBXML_STATIC",
"-DLIBXML_PUSH_ENABLED",
});
if (target.result.os.tag == .windows) {
// NOTE: this should be defined on all targets
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-Werror=implicit-function-declaration",
});
}

View File

@@ -77,9 +77,9 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
try apple_sdk.addPaths(b, lib);
}
var flags = std.ArrayList([]const u8).init(b.allocator);
defer flags.deinit();
try flags.appendSlice(&.{
var flags: std.ArrayList([]const u8) = .empty;
defer flags.deinit(b.allocator);
try flags.appendSlice(b.allocator, &.{
"-DFT2_BUILD_LIBRARY",
"-DFT_CONFIG_OPTION_SYSTEM_ZLIB=1",
@@ -103,7 +103,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
// Libpng
_ = b.systemIntegrationOption("libpng", .{}); // So it shows up in help
if (libpng_enabled) {
try flags.append("-DFT_CONFIG_OPTION_USE_PNG=1");
try flags.append(b.allocator, "-DFT_CONFIG_OPTION_USE_PNG=1");
if (b.systemIntegrationOption("libpng", .{})) {
lib.linkSystemLibrary2("libpng", dynamic_link_opts);

View File

@@ -193,8 +193,8 @@ pub const Face = struct {
) void {
c.FT_Set_Transform(
self.handle,
@constCast(@ptrCast(matrix)),
@constCast(@ptrCast(delta)),
@ptrCast(@constCast(matrix)),
@ptrCast(@constCast(delta)),
);
}
};

View File

@@ -9,6 +9,7 @@ pub const Library = @import("Library.zig");
pub const Error = errors.Error;
pub const Face = face.Face;
pub const LoadFlags = face.LoadFlags;
pub const Tag = tag.Tag;
pub const mulFix = computations.mulFix;

View File

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

View File

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

View File

@@ -36,10 +36,13 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
const optimize = options.optimize;
// Shared library
const lib = b.addSharedLibrary(.{
const lib = b.addLibrary(.{
.name = "gtk4-layer-shell",
.target = target,
.optimize = optimize,
.linkage = .dynamic,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
}),
});
b.installArtifact(lib);

View File

@@ -111,13 +111,13 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
const dynamic_link_opts = options.dynamic_link_opts;
var flags = std.ArrayList([]const u8).init(b.allocator);
defer flags.deinit();
try flags.appendSlice(&.{
var flags: std.ArrayList([]const u8) = .empty;
defer flags.deinit(b.allocator);
try flags.appendSlice(b.allocator, &.{
"-DHAVE_STDBOOL_H",
});
if (target.result.os.tag != .windows) {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DHAVE_UNISTD_H",
"-DHAVE_SYS_MMAN_H",
"-DHAVE_PTHREAD=1",
@@ -127,7 +127,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
// Freetype
_ = b.systemIntegrationOption("freetype", .{}); // So it shows up in help
if (freetype_enabled) {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DHAVE_FREETYPE=1",
// Let's just assume a new freetype
@@ -153,7 +153,7 @@ fn buildLib(b: *std.Build, module: *std.Build.Module, options: anytype) !*std.Bu
}
if (coretext_enabled) {
try flags.appendSlice(&.{"-DHAVE_CORETEXT=1"});
try flags.appendSlice(b.allocator, &.{"-DHAVE_CORETEXT=1"});
lib.linkFramework("CoreText");
module.linkFramework("CoreText", .{});
}

View File

@@ -4,7 +4,7 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const upstream = b.dependency("highway", .{});
const upstream_ = b.lazyDependency("highway", .{});
const module = b.addModule("highway", .{
.root_source_file = b.path("main.zig"),
@@ -21,17 +21,19 @@ pub fn build(b: *std.Build) !void {
.linkage = .static,
});
lib.linkLibCpp();
lib.addIncludePath(upstream.path(""));
module.addIncludePath(upstream.path(""));
if (upstream_) |upstream| {
lib.addIncludePath(upstream.path(""));
module.addIncludePath(upstream.path(""));
}
if (target.result.os.tag.isDarwin()) {
const apple_sdk = @import("apple_sdk");
try apple_sdk.addPaths(b, lib);
}
var flags = std.ArrayList([]const u8).init(b.allocator);
defer flags.deinit();
try flags.appendSlice(&.{
var flags: std.ArrayList([]const u8) = .empty;
defer flags.deinit(b.allocator);
try flags.appendSlice(b.allocator, &.{
// Avoid changing binaries based on the current time and date.
"-Wno-builtin-macro-redefined",
"-D__DATE__=\"redacted\"",
@@ -67,31 +69,33 @@ pub fn build(b: *std.Build) !void {
"-fno-vectorize",
});
if (target.result.os.tag != .windows) {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-fmath-errno",
"-fno-exceptions",
});
}
lib.addCSourceFiles(.{ .flags = flags.items, .files = &.{"bridge.cpp"} });
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
.files = &.{
"hwy/abort.cc",
"hwy/aligned_allocator.cc",
"hwy/nanobenchmark.cc",
"hwy/per_target.cc",
"hwy/print.cc",
"hwy/targets.cc",
"hwy/timer.cc",
},
});
lib.installHeadersDirectory(
upstream.path("hwy"),
"hwy",
.{ .include_extensions = &.{".h"} },
);
if (upstream_) |upstream| {
lib.addCSourceFiles(.{
.root = upstream.path(""),
.flags = flags.items,
.files = &.{
"hwy/abort.cc",
"hwy/aligned_allocator.cc",
"hwy/nanobenchmark.cc",
"hwy/per_target.cc",
"hwy/print.cc",
"hwy/targets.cc",
"hwy/timer.cc",
},
});
lib.installHeadersDirectory(
upstream.path("hwy"),
"hwy",
.{ .include_extensions = &.{".h"} },
);
}
b.installArtifact(lib);

View File

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

View File

@@ -22,9 +22,9 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
var flags = std.ArrayList([]const u8).init(b.allocator);
defer flags.deinit();
try flags.appendSlice(&.{
var flags: std.ArrayList([]const u8) = .empty;
defer flags.deinit(b.allocator);
try flags.appendSlice(b.allocator, &.{
"-DHAVE_CONFIG_H",
"-DLOCALEDIR=\"\"",
});

View File

@@ -46,9 +46,9 @@ pub fn build(b: *std.Build) !void {
}
if (b.lazyDependency("libpng", .{})) |upstream| {
var flags = std.ArrayList([]const u8).init(b.allocator);
defer flags.deinit();
try flags.appendSlice(&.{
var flags: std.ArrayList([]const u8) = .empty;
defer flags.deinit(b.allocator);
try flags.appendSlice(b.allocator, &.{
"-DPNG_ARM_NEON_OPT=0",
"-DPNG_POWERPC_VSX_OPT=0",
"-DPNG_INTEL_SSE_OPT=0",

View File

@@ -4,7 +4,7 @@ pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const upstream = b.dependency("libxml2", .{});
const upstream_ = b.lazyDependency("libxml2", .{});
const lib = b.addLibrary(.{
.name = "xml2",
@@ -16,7 +16,7 @@ pub fn build(b: *std.Build) !void {
});
lib.linkLibC();
lib.addIncludePath(upstream.path("include"));
if (upstream_) |upstream| lib.addIncludePath(upstream.path("include"));
lib.addIncludePath(b.path("override/include"));
if (target.result.os.tag == .windows) {
lib.addIncludePath(b.path("override/config/win32"));
@@ -25,9 +25,9 @@ pub fn build(b: *std.Build) !void {
lib.addIncludePath(b.path("override/config/posix"));
}
var flags = std.ArrayList([]const u8).init(b.allocator);
defer flags.deinit();
try flags.appendSlice(&.{
var flags: std.ArrayList([]const u8) = .empty;
defer flags.deinit(b.allocator);
try flags.appendSlice(b.allocator, &.{
// Version info, hardcoded
comptime "-DLIBXML_VERSION=" ++ Version.number(),
comptime "-DLIBXML_VERSION_STRING=" ++ Version.string(),
@@ -46,7 +46,7 @@ pub fn build(b: *std.Build) !void {
"-DWITHOUT_TRIO=1",
});
if (target.result.os.tag != .windows) {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DHAVE_ARPA_INET_H=1",
"-DHAVE_ARPA_NAMESER_H=1",
"-DHAVE_DL_H=1",
@@ -74,44 +74,46 @@ pub fn build(b: *std.Build) !void {
var nameBuf: [32]u8 = undefined;
const name = std.ascii.upperString(&nameBuf, field.name);
const define = try std.fmt.allocPrint(b.allocator, "-DLIBXML_{s}_ENABLED=1", .{name});
try flags.append(define);
try flags.append(b.allocator, define);
if (std.mem.eql(u8, field.name, "history")) {
try flags.appendSlice(&.{
try flags.appendSlice(b.allocator, &.{
"-DHAVE_LIBHISTORY=1",
"-DHAVE_LIBREADLINE=1",
});
}
if (std.mem.eql(u8, field.name, "mem_debug")) {
try flags.append("-DDEBUG_MEMORY_LOCATION=1");
try flags.append(b.allocator, "-DDEBUG_MEMORY_LOCATION=1");
}
if (std.mem.eql(u8, field.name, "regexp")) {
try flags.append("-DLIBXML_UNICODE_ENABLED=1");
try flags.append(b.allocator, "-DLIBXML_UNICODE_ENABLED=1");
}
if (std.mem.eql(u8, field.name, "run_debug")) {
try flags.append("-DLIBXML_DEBUG_RUNTIME=1");
try flags.append(b.allocator, "-DLIBXML_DEBUG_RUNTIME=1");
}
if (std.mem.eql(u8, field.name, "thread")) {
try flags.append("-DHAVE_LIBPTHREAD=1");
try flags.append(b.allocator, "-DHAVE_LIBPTHREAD=1");
}
}
}
lib.addCSourceFiles(.{
.root = upstream.path(""),
.files = srcs,
.flags = flags.items,
});
if (upstream_) |upstream| {
lib.addCSourceFiles(.{
.root = upstream.path(""),
.files = srcs,
.flags = flags.items,
});
lib.installHeader(
b.path("override/include/libxml/xmlversion.h"),
"libxml/xmlversion.h",
);
lib.installHeadersDirectory(
upstream.path("include"),
"",
.{ .include_extensions = &.{".h"} },
);
lib.installHeader(
b.path("override/include/libxml/xmlversion.h"),
"libxml/xmlversion.h",
);
lib.installHeadersDirectory(
upstream.path("include"),
"",
.{ .include_extensions = &.{".h"} },
);
}
b.installArtifact(lib);
}

View File

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

View File

@@ -68,7 +68,7 @@ pub const MutableArray = opaque {
comptime Elem: type,
value: *const Elem,
) void {
CFArrayAppendValue(self, @constCast(@ptrCast(value)));
CFArrayAppendValue(self, @ptrCast(@constCast(value)));
}
pub fn removeValue(self: *MutableArray, idx: usize) void {

View File

@@ -10,7 +10,7 @@ pub const AttributedString = opaque {
str: *foundation.String,
attributes: *foundation.Dictionary,
) Allocator.Error!*AttributedString {
return @constCast(@ptrCast(c.CFAttributedStringCreate(
return @ptrCast(@constCast(c.CFAttributedStringCreate(
null,
@ptrCast(str),
@ptrCast(attributes),

View File

@@ -17,8 +17,8 @@ pub const Dictionary = opaque {
return @as(?*Dictionary, @ptrFromInt(@intFromPtr(c.CFDictionaryCreate(
null,
@constCast(@ptrCast(if (keys) |slice| slice.ptr else null)),
@constCast(@ptrCast(if (values) |slice| slice.ptr else null)),
@ptrCast(@constCast(if (keys) |slice| slice.ptr else null)),
@ptrCast(@constCast(if (values) |slice| slice.ptr else null)),
@intCast(if (keys) |slice| slice.len else 0),
&c.kCFTypeDictionaryKeyCallBacks,
&c.kCFTypeDictionaryValueCallBacks,

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