622 Commits

Author SHA1 Message Date
Kat
7d5be8e960 i18n: update Russian translation (#8473)
Part of #8344
2025-09-03 04:12:21 +00:00
Mitchell Hashimoto
d05ec81b86 apprt/gtk-ng: must quit scenarios should quit immediately (#8500)
Fixes #8495

We were incorrectly calling graceful quit under must quit scenarios.
This would do things like confirm quit by inspecting for running
processes. However, must quit scenarios (namely when all windows are
destroyed) should quit immediately without any checks because the
dispose process takes more event loop ticks to fully finish.
2025-09-02 20:46:35 -07:00
Mitchell Hashimoto
f016b79f22 apprt/gtk-ng: must quit scenarios should quit immediately
Fixes #8495

We were incorrectly calling graceful quit under must quit scenarios.
This would do things like confirm quit by inspecting for running
processes. However, must quit scenarios (namely when all windows are
destroyed) should quit immediately without any checks because the
dispose process takes more event loop ticks to fully finish.
2025-09-02 20:42:01 -07:00
Ivan Bastrakov
52f5ab1a36 i18n: update Russian translation 2025-09-03 01:57:25 +03:00
Mitchell Hashimoto
8d11c08db3 feat: add selection-clear-on-copy configuration option (#8462)
Addresses issue: Add selection-clear-on-copy configuration #8407

Added configuration option `selection-clear-on-copy` that matches with
the `selection-clear-on-typing` option.
And `copy-on-select` is ignored when `selection-clear-on-copy` is true
regardless of whether `copy-on-select` is set to true or clipboard.
Also `.copy_to_clipboard` binding action was refactored to use
`copySelectionToClipboards` for consistent behavior.

> Consulted with Copilot (Claude Sonnet 4) to understand the control
flow of copy operations and help write the docs. Solution was authored
and implemented by me.
2025-09-02 14:55:46 -07:00
Toufiq Shishir
90c0fc2590 feat: add selection-clear-on-copy configuration 2025-09-02 14:48:47 -07:00
Mitchell Hashimoto
e909e28876 Compare fields directly instead of PackedStyle (#8489)
This is a small, but I think worthwhile micro optimization in style.zig,
I uncovered while investigating wider ranging optimizations in the
rendering section.

For me it results in ~4-5% increase in fps for DOOM-fire-zig benchmark,
which maximally stresses this code path.

Comparing the fields directly is actually faster than PackedStyle.

I wrote the code in style.zig, claude 4 wrote the benchmark, all PR
responses will be generated by jcm-slow-1


Style.eql Benchmark Comparison
==============================

Test: Small (1K pairs, 50% equal)
--------------------------------------------------
New implementation:
  Iterations: 49937
  Duration: 500.01 ms
  Throughput: 99872402 comparisons/sec
Old implementation:
  Iterations: 8508
  Duration: 500.06 ms
  Throughput: 17014026 comparisons/sec
Performance improvement:
  Speedup: 5.87x
  Improvement: +487.0%

Test: Medium (10K pairs, 50% equal)
--------------------------------------------------
New implementation:
  Iterations: 4435
  Duration: 500.09 ms
  Throughput: 88684746 comparisons/sec
Old implementation:
  Iterations: 850
  Duration: 500.50 ms
  Throughput: 16983017 comparisons/sec
Performance improvement:
  Speedup: 5.22x
  Improvement: +422.2%

Test: Large (50K pairs, 50% equal)
--------------------------------------------------
New implementation:
  Iterations: 861
  Duration: 500.41 ms
  Throughput: 86030144 comparisons/sec
Old implementation:
  Iterations: 171
  Duration: 501.70 ms
  Throughput: 17041989 comparisons/sec
Performance improvement:
  Speedup: 5.05x
  Improvement: +404.8%

Test: Mostly equal (10K pairs, 90% equal)
--------------------------------------------------
New implementation:
  Iterations: 4608
  Duration: 500.03 ms
  Throughput: 92154471 comparisons/sec
Old implementation:
  Iterations: 854
  Duration: 500.45 ms
  Throughput: 17064744 comparisons/sec
Performance improvement:
  Speedup: 5.40x
  Improvement: +440.0%

Test: Mostly different (10K pairs, 10% equal)
--------------------------------------------------
New implementation:
  Iterations: 4065
  Duration: 500.03 ms
  Throughput: 81294960 comparisons/sec
Old implementation:
  Iterations: 848
  Duration: 500.21 ms
  Throughput: 16952948 comparisons/sec
Performance improvement:
  Speedup: 4.80x
  Improvement: +379.5%

Test: Same flags (10K pairs, 50% equal)
--------------------------------------------------
New implementation:
  Iterations: 2799
  Duration: 500.00 ms
  Throughput: 55979776 comparisons/sec
Old implementation:
  Iterations: 859
  Duration: 500.13 ms
  Throughput: 17175672 comparisons/sec
Performance improvement:
  Speedup: 3.26x
  Improvement: +225.9%
2025-09-02 14:37:30 -07:00
Jesse Miller
cf0390bab5 Use comptime for eql() to ensure Style struct coverage. 2025-09-02 15:14:42 -06:00
Jesse Miller
4614e5fdad Zig 0.14+ can directly compare packed structs. 2025-09-02 14:58:21 -06:00
Mitchell Hashimoto
ce94bb9f6a macOS: firstRect should return full rect width/height (#8492)
Fixes #2473

This commit changes `ghostty_surface_ime_point` to return a full rect
with the width/height calculated for the preedit.

The `firstRect` function, which calls `ghostty_surface_ime_point` was
previously setting the width/height to zero. macOS didn't like this. We
then changed it to just hardcode it to width/height of one cell. This
worked but made it so the IME cursor didn't follow the preedit.

The result is shown in the video below. Notice the dictation icon
follows the text properly:



https://github.com/user-attachments/assets/81be8c63-9f0a-49b7-ac30-2db930beb238
2025-09-02 13:28:08 -07:00
Jesse Miller
ac104a3dfc zig fmt 2025-09-02 14:14:06 -06:00
Mitchell Hashimoto
16e47e7586 fix(font): detect and reject improper advance for icwidth (#8491)
Fixes #8481

Explained in code comments, basically the NF patcher can produce fonts
that have CJK characters with 1-cell advances, which screws up fallback
font scaling; fixed by not counting the ic width metric if the width of
the glyph is greater than the advance width.

> [!NOTE]
> As follow-on work to this it may be worth setting limits for scaling,
so you can't have one font scaled like twice as large as the primary
font, since that's almost always going to indicate something is very
wrong.
2025-09-02 13:09:07 -07:00
Mitchell Hashimoto
e8217aa007 macOS: firstRect should return full rect width/height
Fixes #2473

This commit changes `ghostty_surface_ime_point` to return a full rect
with the width/height calculated for the preedit.

The `firstRect` function, which calls `ghostty_surface_ime_point` was
previously setting the width/height to zero. macOS didn't like this. We
then changed it to just hardcode it to width/height of one cell. This
worked but made it so the IME cursor didn't follow the preedit.
2025-09-02 13:08:46 -07:00
Qwerasd
9aa1698e5a font: log warning when rejecting ic_width 2025-09-02 13:47:59 -06:00
Mitchell Hashimoto
3664ee9f87 macOS: Notify macOS of cell width/height for firstRect (#8490)
Related to #2473

This fixes an issue where the dictation icon didn't show the language
picker.
2025-09-02 12:38:50 -07:00
Qwerasd
a72995590b fix(font): detect and reject improper advance for icwidth 2025-09-02 13:33:33 -06:00
Mitchell Hashimoto
2bf0d3f4c7 macOS: Notify macOS of cell width/height for firstRect
Related to #2473

This fixes an issue where the dictation icon didn't show the language 
picker.
2025-09-02 12:26:52 -07:00
Mitchell Hashimoto
4af290d5f0 fix(renderer): kitty images should all be processed (#8488)
When processing kitty images in a loop in a few places we were returning
under certain conditions where we should instead have just continued the
loop. This caused serious problems for kitty images, especially for apps
that used multiple images on screen at once.

... I have no clue how I originally wrote this code and didn't see such
a trivial mistake, I think I was sleep deprived or something.

Should fix #8471
2025-09-02 12:14:11 -07:00
Qwerasd
ef7857f9be fix(renderer): kitty images should all be processed
When processing kitty images in a loop in a few places we were returning
under certain conditions where we should instead have just continued the
loop. This caused serious problems for kitty images, especially for apps
that used multiple images on screen at once.

... I have no clue how I originally wrote this code and didn't see such
a trivial mistake, I think I was sleep deprived or something.
2025-09-02 12:42:34 -06:00
Jesse Miller
7dcf2c9b62 Compare fields directly instead of PackedStyle
Comparing the fields directly is actually faster than PackedStyle
2025-09-02 12:05:30 -06:00
Mitchell Hashimoto
d316449ebf config: bind both physical digit plus unicode digit for goto_tab (#8486)
Fixes #8478

The comments explain this.
2025-09-02 09:12:08 -07:00
Mitchell Hashimoto
650028fa9f config: bind both physical digit plus unicode digit for goto_tab
Fixes #8478

The comments explain this.
2025-09-02 09:00:58 -07:00
Mitchell Hashimoto
5ef6412823 macOS: Progress bar for OSC9 progress reports (#8477)
#7975 but for macOS. The behavior and even the look is almost identical:


https://github.com/user-attachments/assets/b7e0b370-3a30-443d-89ae-08209d2c9b89

Similar to GTK, it'll remove the progress bar state after 15 seconds. 

AI disclaimer: Claude code produced most of this code. I reviewed all
the lines and understand them completely.
2025-08-31 20:51:54 -07:00
Mitchell Hashimoto
0b58830882 macOS: Progress bar for OSC9 progress reports 2025-08-31 20:42:34 -07:00
Mitchell Hashimoto
a41ec17b61 build(deps): bump actions/checkout from 4.3.0 to 5.0.0 (#8476)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.3.0
to 5.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
<li>Prepare v5.0.0 release by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2238">actions/checkout#2238</a></li>
</ul>
<h2>⚠️ Minimum Compatible Runner Version</h2>
<p><strong>v2.327.1</strong><br />
<a
href="https://github.com/actions/runner/releases/tag/v2.327.1">Release
Notes</a></p>
<p>Make sure your runner is updated to this version or newer to use this
release.</p>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4...v5.0.0">https://github.com/actions/checkout/compare/v4...v5.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>V5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>V4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
<li>Pin actions/checkout's own workflows to a known, good, stable
version. by <a href="https://github.com/jww3"><code>@​jww3</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1776">actions/checkout#1776</a></li>
</ul>
<h2>v4.1.6</h2>
<ul>
<li>Check platform to set archive extension appropriately by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1732">actions/checkout#1732</a></li>
</ul>
<h2>v4.1.5</h2>
<ul>
<li>Update NPM dependencies by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1703">actions/checkout#1703</a></li>
<li>Bump github/codeql-action from 2 to 3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1694">actions/checkout#1694</a></li>
<li>Bump actions/setup-node from 1 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1696">actions/checkout#1696</a></li>
<li>Bump actions/upload-artifact from 2 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1695">actions/checkout#1695</a></li>
<li>README: Suggest <code>user.email</code> to be
<code>41898282+github-actions[bot]@users.noreply.github.com</code> by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1707">actions/checkout#1707</a></li>
</ul>
<h2>v4.1.4</h2>
<ul>
<li>Disable <code>extensions.worktreeConfig</code> when disabling
<code>sparse-checkout</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1692">actions/checkout#1692</a></li>
<li>Add dependabot config by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1688">actions/checkout#1688</a></li>
<li>Bump the minor-actions-dependencies group with 2 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1693">actions/checkout#1693</a></li>
<li>Bump word-wrap from 1.2.3 to 1.2.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1643">actions/checkout#1643</a></li>
</ul>
<h2>v4.1.3</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="08c6903cd8"><code>08c6903</code></a>
Prepare v5.0.0 release (<a
href="https://redirect.github.com/actions/checkout/issues/2238">#2238</a>)</li>
<li><a
href="9f265659d3"><code>9f26565</code></a>
Update actions checkout to use node 24 (<a
href="https://redirect.github.com/actions/checkout/issues/2226">#2226</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/checkout/compare/v4.3.0...08c6903cd8c0fde910a37f88322edcfb5dd907a8">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.3.0&new-version=5.0.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-08-31 19:50:03 -07:00
dependabot[bot]
c535d0a664 build(deps): bump actions/checkout from 4.3.0 to 5.0.0
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.3.0 to 5.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4.3.0...08c6903cd8c0fde910a37f88322edcfb5dd907a8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-01 00:47:33 +00:00
Mitchell Hashimoto
2009ea511d feat: added faint-opacity option (#8472)
This pull request adds the `--faint-opacity` option, as discussed in
#7637.

The default value of the option is also changed from `0.68` to `0.5` for
greater consistency with other popular terminal emulators.
2025-08-31 13:45:26 -07:00
Mitchell Hashimoto
d8578a9ee2 fix: correct the cursor Y position value exposed to shader uniforms (#8122)
Fix for discussion #8113

The cursor Y position value exposed to the shader uniforms was
incorrectly calculated. As per the doc in cell_text.v.glsl: In order to
get the top left of the glyph, we compute an offset based on the
bearings. The Y bearing is the distance from the bottom of the cell to
the top of the glyph, so we subtract it from the cell height to get the
y offset.

This calculation was mistakenly left out of the original code.

This will ensure that the custom shaders using
iCurrentCursor/iPreviousCursor get the correct Y coordinate representing
the top-left corner of the cursor rectangle, matching the documented
uniform behavior
2025-08-31 11:32:59 -07:00
Qwerasd
0d30f859bd renderer: clarify and correct custom shader cursor position math
This math was incorrect from the start, the previous fix helped OpenGL
but broke positioning under Metal; this commit fixes the math to be
correct under both backends and adds comments explaining exactly what's
going on.
2025-08-31 11:44:10 -06:00
Pavel Ivanov
650095e7e9 fix: changed default faint-opacity value to 0.5 2025-08-31 17:21:00 +02:00
Pavel Ivanov
6319464cfb refactor: move faint-opacity clamping to config finalization 2025-08-31 17:19:51 +02:00
Pavel Ivanov
fc6266133f feat: added faint-opacity option 2025-08-31 15:00:29 +02:00
Mitchell Hashimoto
a51a956bdb Update iTerm2 colorschemes (#8470)
Upstream revision:
6cdbc8501d
2025-08-30 21:01:10 -07:00
mitchellh
c94805f0aa deps: Update iTerm2 color schemes 2025-08-31 00:16:30 +00:00
Mitchell Hashimoto
937d17cc35 ci: add freebsd tests (#8466) 2025-08-30 12:59:01 -07:00
Jeffrey C. Ollie
0bc90b2a20 ci: build on freebsd 2025-08-30 13:58:25 -05:00
Jeffrey C. Ollie
75e3835a9e gtk-ng: ensure CSS works on both 4.14 and 4.16+ (#8459)
Ghostty 1.2 needs to support GTK 4.14 because that's the version that
ships with Ubuntu 24.04.

This PR ensures that any GTK 4.16 CSS features are not used in any
static CSS and that the runtime CSS loading handles both 4.14 and 4.16+
appropriately.
2025-08-30 10:41:59 -05:00
Jeffrey C. Ollie
d1e01ec5c3 gtk-ng: ensure CSS works on both 4.14 and 4.16+
Ghostty 1.2 needs to support GTK 4.14 because that's the version that
ships with Ubuntu 24.04.

This PR ensures that any GTK 4.16 CSS features are not used in any
static CSS and that the runtime CSS loading handles both 4.14 and 4.16+
appropriately.
2025-08-30 09:54:40 -05:00
Mitchell Hashimoto
b0d9b0dee0 build(deps): bump namespacelabs/nscloud-cache-action from 1.2.16 to 1.2.17 (#8449)
Bumps
[namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action)
from 1.2.16 to 1.2.17.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/namespacelabs/nscloud-cache-action/releases">namespacelabs/nscloud-cache-action's
releases</a>.</em></p>
<blockquote>
<h2>v1.2.17</h2>
<h2>What's Changed</h2>
<ul>
<li>Delete existing files at path before creating bind mount, this was
already handled correctly for existing directories but not for
files</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/namespacelabs/nscloud-cache-action/compare/v1.2.16...v1.2.17">https://github.com/namespacelabs/nscloud-cache-action/compare/v1.2.16...v1.2.17</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a289cf5d2f"><code>a289cf5</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/33">#33</a>
from namespacelabs/delete-existing-files-at-path-befor...</li>
<li><a
href="3851f57081"><code>3851f57</code></a>
Delete existing files at path before creating bind mount</li>
<li><a
href="58efedf646"><code>58efedf</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/32">#32</a>
from namespacelabs/delete-existing-files-at-path-befor...</li>
<li><a
href="5e60691b8f"><code>5e60691</code></a>
Delete existing files at path before creating bind mount</li>
<li>See full diff in <a
href="305bfa7ea9...a289cf5d2f">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.16&new-version=1.2.17)](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-08-29 07:08:26 -07:00
Mitchell Hashimoto
e6b019b197 build(deps): bump cachix/install-nix-action from 31.5.2 to 31.6.0 (#8450)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.5.2 to 31.6.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.6.0</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): bump actions/checkout from 4 to 5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/cachix/install-nix-action/pull/249">cachix/install-nix-action#249</a></li>
<li>docs: add example for <code>nix develop</code> by <a
href="https://github.com/jennydaman"><code>@​jennydaman</code></a> in <a
href="https://redirect.github.com/cachix/install-nix-action/pull/248">cachix/install-nix-action#248</a></li>
<li>nix: 2.30.2 -&gt; 2.31.0 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/250">cachix/install-nix-action#250</a>
Release notes: <a
href="https://discourse.nixos.org/t/nix-2-31-0-released/68465">https://discourse.nixos.org/t/nix-2-31-0-released/68465</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/jennydaman"><code>@​jennydaman</code></a> made
their first contribution in <a
href="https://redirect.github.com/cachix/install-nix-action/pull/248">cachix/install-nix-action#248</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31.5.2...v31.6.0">https://github.com/cachix/install-nix-action/compare/v31.5.2...v31.6.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="56a7bb7b56"><code>56a7bb7</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/250">#250</a>
from cachix/create-pull-request/patch</li>
<li><a
href="c04e864467"><code>c04e864</code></a>
nix: 2.30.2 -&gt; 2.31.0</li>
<li><a
href="9aaadd8b85"><code>9aaadd8</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/248">#248</a>
from jennydaman/patch-1</li>
<li><a
href="a23271bac0"><code>a23271b</code></a>
Reword README.md section on <code>nix develop</code></li>
<li><a
href="f02d365678"><code>f02d365</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/249">#249</a>
from cachix/dependabot/github_actions/actions/checkout-5</li>
<li><a
href="b4dc112147"><code>b4dc112</code></a>
chore(deps): bump actions/checkout from 4 to 5</li>
<li><a
href="ca6a0fa535"><code>ca6a0fa</code></a>
Add example for <code>nix develop</code></li>
<li><a
href="96bd9f39e4"><code>96bd9f3</code></a>
ci: update nixpkgs channel used in tests</li>
<li><a
href="92ffed7f0d"><code>92ffed7</code></a>
ci: make test workflow dispatchable</li>
<li>See full diff in <a
href="fc6e360bed...56a7bb7b56">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.5.2&new-version=31.6.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-08-29 07:08:09 -07:00
Guilherme Nandi Tiscoski
5761f66f35 i18n: update pt_BR translations (#8391)
relative to https://github.com/ghostty-org/ghostty/issues/8344
2025-08-29 13:26:37 +00:00
trag1c
a5eef1d227 i18n: Updating Irish translation for Ghostty 1.2 (#8349)
This Pull Request updates 5 translation strings for Ghostty 1.2 as per
#8344
2025-08-29 11:01:00 +02:00
dependabot[bot]
85e642097a build(deps): bump cachix/install-nix-action from 31.5.2 to 31.6.0
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.5.2 to 31.6.0.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](fc6e360bed...56a7bb7b56)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-29 00:08:00 +00:00
dependabot[bot]
bed350f0be build(deps): bump namespacelabs/nscloud-cache-action
Bumps [namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action) from 1.2.16 to 1.2.17.
- [Release notes](https://github.com/namespacelabs/nscloud-cache-action/releases)
- [Commits](305bfa7ea9...a289cf5d2f)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-29 00:07:51 +00:00
Mitchell Hashimoto
460fcc1344 docs: reorganize and separate out HACKING.md for technical instructions (#8445)
Also did some copy-editing and removed some things that haven't been
present in the codebase for a while (I thought we nuked conformance
stuff in 1.1 already...?)
2025-08-28 15:20:23 -07:00
Leah Amelia Chen
f91e6f1764 docs: better integrate CONTRIBUTING into the README 2025-08-29 06:14:41 +08:00
Leah Amelia Chen
f802d33652 docs: divide content more evenly between CONTRIBUTING and HACKING
CONTRIBUTING should now solely be about the contribution *process*
while HACKING goes into the technical details
2025-08-29 06:14:41 +08:00
Leah Amelia Chen
2701932475 docs: separate out HACKING.md from README.md
Also did some copy-editing and removed some things that haven't been
present in the codebase for a while (I thought we nuked conformance
stuff in 1.1 already...?)
2025-08-29 06:14:36 +08:00
Mitchell Hashimoto
6cfd89e248 macOS: Always require confirmation when executing a script via open (Finder, etc.) (#8442)
Right now, passing a file path to Ghostty will always execute it
unconditionally. This has various risks associated with it. I think we
can mitigate a lot of risks in the future by inspecting what is being
executed, but to be safe now we should always ask for confirmation.
2025-08-28 13:12:48 -07:00
Mitchell Hashimoto
9962e523a8 some typos 2025-08-28 12:58:07 -07:00
Mitchell Hashimoto
04956f3dc1 macos: require confirmation to run any script 2025-08-28 12:34:04 -07:00
Mitchell Hashimoto
f1ea30dcf1 macos: when executing a script directly, always wait after command 2025-08-28 11:26:33 -07:00
trag1c
d3cadf2495 i18n: update bg_BG translations (#8345)
Part of https://github.com/ghostty-org/ghostty/issues/8344
2025-08-27 23:16:15 +02:00
Mitchell Hashimoto
7106d71a42 apprt/gtk-ng: "cancel" should be default close response for dialog (#8427)
Fixes #8424

This is the response that will be sent when "escape" is pressed.

This also fixes a null ptr deref that was possible when this fix wasn't
in.
2025-08-27 09:48:19 -07:00
Mitchell Hashimoto
f54f2dc7f3 apprt/gtk-ng: "cancel" should be default close response for dialog
Fixes #8424

This is the response that will be sent when "escape" is pressed.

This also fixes a null ptr deref that was possible when this fix wasn't
in.
2025-08-27 09:42:35 -07:00
Mitchell Hashimoto
5013d028a3 terminal: fix csi parsing (#8417)
Make `MAX_PARAMS` public and increase CSI parameter limit from 16 to 24.
Fix potential out-of-bounds read in SGR partial sequence extraction.

Related discussion:
https://github.com/ghostty-org/ghostty/discussions/5198

DISCLAIMER: the tests were written with Claude Code's help.
2025-08-27 07:20:16 -07:00
Mitchell Hashimoto
adfc93047c terminal: fix up some tests to be more robust 2025-08-27 07:15:42 -07:00
Adrià Arrufat
a3f4997fbc fix(terminal): handle CSI/SGR with many parameters
Adds tests to ensure CSI and SGR sequences with 17 or more parameters are correctly parsed, fixing a bug where later parameters were previously dropped.
2025-08-27 07:10:17 -07:00
Adrià Arrufat
56d3fd872e fix(terminal): improve CSI parameter parsing
Make `MAX_PARAMS` public and increase CSI parameter limit from 16 to 24.
Fix potential out-of-bounds read in SGR partial sequence extraction.
2025-08-27 07:10:17 -07:00
Mitchell Hashimoto
58e85bf133 macos: use visible frame for quick terminal sizing calculation (#8423)
Fixes #8418

This fixes issues where left/right positions would be cut off from the
menu bar. And makes it so that size 100%,100% doesn't overflow into the
non-visible space of the edge of the screen.

I didn't just copy and paste, I tested each of these code paths.
2025-08-27 07:06:55 -07:00
Mitchell Hashimoto
19a27383f8 macos: use visible frame for quick terminal sizing calculation
Fixes #8418

This fixes issues where left/right positions would be cut off from the
menu bar. And makes it so that size 100%,100% doesn't overflow into the
non-visible space of the edge of the screen.
2025-08-27 06:59:02 -07:00
reo101
8fa065512f i18n: update bg_BG translations 2025-08-27 16:39:58 +03:00
Jeffrey C. Ollie
6530107e3b config: add entry for scroll-to-bottom (#8412)
Related #8408

(EDIT @mitchellh: Removed "Fixes" to avoid closing)
2025-08-26 22:26:03 -05:00
Jeffrey C. Ollie
87056a2600 surface: store entire scroll-to-bottom struct 2025-08-26 22:04:23 -05:00
Jeffrey C. Ollie
6a128189e3 osc: conemu cleanup (#8413)
- Add more comments, and make existing ones more consistent.
- Rename commands so they consitently have a `conemu_` prefix.
- Ensure that OSC 9 desktop notifications can be sent in the maximum
number of circumstances. There are still many notifications that can't
be sent because of our support for the ConEmu OSCs but that's the
tradeoff we have chosen. We recommend that you switch to OSC 777 to
ensure desktop notifications can be sent in all circumstances.
- Make sure that the tests that exercise the ConEmu OSCs have a
consistent naming structure. That will make them easier to find through
searching as well as make it easier to filter only the ConEmu OSC tests.
- Add more tests to make sure that desktop notifications are sent
properly.
2025-08-26 22:03:42 -05:00
Jeffrey C. Ollie
2490171304 surface: implement scroll-to-bottom=keystroke 2025-08-26 21:48:18 -05:00
Jeffrey C. Ollie
31c96d906a config: add entry for scroll-to-bottom
Fixes #8408
2025-08-26 21:48:18 -05:00
Jeffrey C. Ollie
64d8492836 osc: conemu cleanup
- Add more comments, and make existing ones more consistent.
- Rename commands so they consitently have a `conemu_` prefix.
- Ensure that OSC 9 desktop notifications can be sent in the maximum
  number of circumstances. There are still many notifications that can't
  be sent because of our support for the ConEmu OSCs but that's the
  tradeoff we have chosen. We recommend that you switch to OSC 777 to
  ensure desktop notifications can be sent in all circumstances.
- Make sure that the tests that exercise the ConEmu OSCs have a
  consistent naming structure. That will make them easier to find
  through searching as well as make it easier to filter only the ConEmu
  OSC tests.
- Add more tests to make sure that desktop notifications are sent
  properly.
2025-08-26 21:28:50 -05:00
Mitchell Hashimoto
c1ab41afac osc: parse OSC 9;6 gui macros (#8410) 2025-08-26 14:56:42 -07:00
Jeffrey C. Ollie
f047db6a3b osc: parse OSC 9;6 gui macros 2025-08-26 16:28:25 -05:00
Mitchell Hashimoto
cd8455c24b apprt/gtk-ng: show error widget if GLArea fails to initialize (#8390)
If GTK can't acquire an OpenGL context, this shows a message.
Previously, we would only log a warning which was difficult to find. The
GUI previously was the default GTK view which showed "Failed to acquire
EGL display" which was equally confusing.

This is a draft. There are TODOs (listed below).

## TODO

- [x] Disable context menu in error state
- [x] Use property to bind to unhealthy state instead of directly
setting stack child
- [x] Create a web page and put that in the error description
- [x] Set non-transparent background in error state
- [x] Bug where closing the window isn't exiting Ghostty
2025-08-26 12:07:42 -07:00
Mitchell Hashimoto
4d6269a859 apprt/gtk-ng: show error widget if GLArea fails to initialize
If GTK can't acquire an OpenGL context, this shows a message.
Previously, we would only log a warning which was difficult to find. The
GUI previously was the default GTK view which showed "Failed to acquire
EGL display" which was equally confusing.
2025-08-26 12:03:02 -07:00
Mitchell Hashimoto
3fb17dc802 scroll: round up fractional mouse scroll ticks (#7185)
Scrolling with a mouse on macos doesn't work very well when doing small,
single tick scrolls. macos attempts to mimic precision scrolling by
changing the magnitude of the scroll deltas based on scrolling speed.
Slow scrolls only send deltas with a magnitude of 0.1, which isn't
enough to send a single scroll event with the default scroll multiplier
of 3. Changing the scroll multiplier to 10 as a workaround (so even
single small scroll ticks are enough to register a scroll event) cause
scrolling to be way too fast if the scroll speed is ramped up.

This commit causes the yoffset delta to be rounded out to at least a
magnitude of 1 in the appropriate direction. Single scroll ticks now
register as a single vertical cell scroll event, but as scroll speed is
ramped up, the true delta reported to the surface is used again. Setting
a scroll multiplier of 1 with the changes here makes mouse scrolling
feel just as good as trackpad precision scrolling.
2025-08-26 11:07:12 -07:00
John Drouhard
6cf636b1ad scroll: round up fractional mouse scroll ticks
Scrolling with a mouse on macos doesn't work very well when doing small,
single tick scrolls. macos attempts to mimic precision scrolling by
changing the magnitude of the scroll deltas based on scrolling speed.
Slow scrolls only send deltas with a magnitude of 0.1, which isn't
enough to send a single scroll event with the default scroll multiplier
of 3. Changing the scroll multiplier to 10 as a workaround (so even
single small scroll ticks are enough to register a scroll event) cause
scrolling to be way too fast if the scroll speed is ramped up.

This commit causes the yoffset delta to be rounded out to at least a
magnitude of 1 in the appropriate direction. For small single scroll
ticks, it's enough to register a scroll event, but as scroll speed is
ramped up, the true delta reported to the surface is used again. Setting
a scroll multiplier of 1 with the changes here makes mouse scrolling
feel just as good as trackpad precision scrolling.
2025-08-26 11:02:36 -07:00
Mitchell Hashimoto
673afd193b macos: fix quick terminal fullscreen crash bug (#8093)
Fullscreen on quick terminal was failing with a crash, when it tried
to save the state of a non-existent toolbar and its accessory view
controllers.

See #7980
2025-08-26 10:51:31 -07:00
Mitchell Hashimoto
ff61cad1e2 gtk-ng: implement close_tab:other keybind (#8403) 2025-08-26 10:48:55 -07:00
Mitchell Hashimoto
520eaec61c macos: fix quick terminal issue where closing while fullscreen 2025-08-26 10:40:41 -07:00
Alexander Lais
e676eae640 macos: fix quick terminal fullscreen
Fullscreen on quick terminal was failing with a crash, when it tried
to save the state of a non-existent toolbar and its accessory view
controllers.
2025-08-26 10:36:06 -07:00
Mitchell Hashimoto
830194d436 Quick Terminal Sizing on macOS (#8402)
Fixes #8398
Fixes #2384 

This is just #7576 rebased with some style changes. For some reason I
couldn't update that PR.
2025-08-26 10:31:02 -07:00
Jeffrey C. Ollie
6f630a27be gtk-ng: implement close_tab:other keybind 2025-08-26 12:22:45 -05:00
Mitchell Hashimoto
ae48f323d7 macos: style changes for quick terminal sizing 2025-08-26 10:20:16 -07:00
Mitchell Hashimoto
a90bf58080 config: change quick terminal size C layout to tagged union 2025-08-26 09:52:26 -07:00
Friedrich Stoltzfus
6a78f9c0c0 Merge branch 'ghostty-org:main' into quick-term-initial-size 2025-08-26 09:47:31 -07:00
Friedrich Stoltzfus
466fdfffe6 macOS: rename c struct, relocate QuickTerminalSize file
Renamed the ghostty_quick_terminal_size_u to
ghostty_quick_terminal_size_s and moved the QuickTerminalSize file to
the Ghostty folder as requested.
2025-08-26 09:47:31 -07:00
Friedrich Stoltzfus
58e7400ea5 macOS: Round quick terminal window position coordinates
This resolves an issue where the right side of the quick terminal would
not resize equally to the left side if adjusting the width from the left
side.
2025-08-26 09:47:31 -07:00
Friedrich Stoltzfus
0afadeea5f use decl literals as suggested
Applied from the code review

Co-authored-by: Leah Amelia Chen <github@acc.pluie.me>
2025-08-26 09:47:31 -07:00
Friedrich Stoltzfus
e5ad6603f4 Merge branch 'main' into quick-term-initial-size 2025-08-26 09:47:31 -07:00
Friedrich Stoltzfus
7cc0728fe5 macOS: enable quick terminal manual resizing
You can now resize the quick terminal both vertically and horizontally. To incorporate adjusting the custom secondary size on the quick terminal we needed to have the ability to resize the width (if from top, bottom, or center), and height (if from right, left, or center). The quick terminal will retain the user's manually adjusted size while the app is open. A new feature with this is that when the secondary size is adjusted (or primary if the quick terminal is center), the size will increase or decrease on both sides of the terminal.
2025-08-26 09:47:31 -07:00
Friedrich Stoltzfus
17f7f204e1 macOS: update zig and c structs for quick terminal size
Applying the feedback given by @pluiedev to use an enum to specify the
type of quick terminal size configuration given (pixels or percentage).
Updated the Swift code to work with the enum as well.
2025-08-26 09:47:31 -07:00
Friedrich Stoltzfus
63cd424678 macOS: Add support for quick terminal sizing configuration
Added C bindings for the already existing quick-terminal-size
configuration. Created a new QuickTerminalSize struct to hold these
values in Swift. Updated the QuickTerminal implementation to use the
user's configuration if supplied. Retains defaults. Also adds support to
customize the width of the quick terminal (height if quick terminal is
set to right or left).
2025-08-26 09:47:31 -07:00
Mitchell Hashimoto
5c464e855d parameterize close_tab (#8389)
- Add mode (`this`/`other`) parameter to `close_tab` keybind/apprt
action.
- Keybinds will default to `this` if not specified, eliminating backward
compatibility issues (`keybind=x=close_tab` ===
`keybind=x=close_tab:this`).
- Remove `close_other_tabs` keybind and apprt action.

Replaces #8380
2025-08-26 09:28:16 -07:00
Aindriú Mac Giolla Eoin
9c725187e1 Updating two strings 2025-08-26 15:47:16 +01:00
trag1c
4630369f87 i18n: update Ukrainian translation (#8379) 2025-08-26 10:44:58 +02:00
Mitchell Hashimoto
5b0801cbc9 osc 9: allow single character notifications (#8396) 2025-08-25 19:35:51 -07:00
Jeffrey C. Ollie
3320a081b4 osc 9: allow single character notifications 2025-08-25 19:27:27 -05:00
trag1c
9a56e77937 i18n: add new translations in fr_FR (#8378)
relative to #8344
2025-08-26 00:32:56 +02:00
Marija Gjorgjieva Gjondeva
a471bac782 Update macedonian translation strings (#8392)
Updated new translation strings for version 1.2.

#8344
2025-08-25 21:03:43 +00:00
Jeffrey C. Ollie
14a3765916 cli: show colors in +list-colors if possible (#8393)
Fixes #8386

This is a fairly simple implementaion, there's no interactivity or
searching. It will adapt the number of columns to the available width of
the display though.

Will fallback to a plain text dump if there's no tty or the `--plain`
argument is specified on the CLI.

<img width="2112" height="1278" alt="image"
src="https://github.com/user-attachments/assets/0dbeec72-2092-4ed5-b1ed-0df43e5c64a3"
/>
2025-08-25 15:51:03 -05:00
Jeffrey C. Ollie
ca06b95f65 cli: show colors in +list-colors if possible
Fixes #8386

This is a fairly simple implementaion, there's no interactivity or
searching. It will adapt the number of columns to the available width of
the display though.

Will fallback to a plain text dump if there's no tty or the `--plain`
argument is specified on the CLI.
2025-08-25 15:00:32 -05:00
trag1c
d659bdcfdd i18n: add missing de_DE translations (#8351)
Part of #8344.
2025-08-25 21:37:46 +02:00
Volodymyr Chernetskyi
754bb4011a i18n: add missing coma 2025-08-25 19:59:46 +02:00
Volodymyr Chernetskyi
11d845ce17 i18n: shorten Ukrainian translations 2025-08-25 19:57:08 +02:00
Robin
c629ea674c i18n: add missing de_DE translations 2025-08-25 19:38:54 +02:00
Volodymyr Chernetskyi
f8d69e5baf i18n: use native Ukrainian word for "config" 2025-08-25 19:33:19 +02:00
Volodymyr Chernetskyi
c396c25898 i18n: shorten Ukrainian translation for "split" 2025-08-25 19:23:26 +02:00
Jeffrey C. Ollie
e98e868265 close-tab: style-fixes 2025-08-25 11:56:17 -05:00
Jeffrey C. Ollie
52a25e9c69 parameterize close_tab
- Add mode (`this`/`other`) parameter to `close_tab` keybind/apprt action.
- Keybinds will default to `this` if not specified, eliminating backward
  compatibility issues (`keybind=x=close_tab` === `keybind=x=close_tab:this`).
- Remove `close_other_tabs` keybind and apprt action.
2025-08-25 11:00:26 -05:00
Mitchell Hashimoto
8aa0b4c92a gtk-ng: fix setting/unsetting of urgency (#8376)
- Don't set urgency on windows that are the topmost window.
- Turn off urgency on windows that become the topmost window.

Fixes #8373
2025-08-25 07:20:15 -07:00
Jeffrey C. Ollie
8a14f21325 gtk-ng: fix setting/unsetting of urgency
- Don't set urgency on windows that are the topmost window.
- Turn off urgency on windows that become the topmost window.

Fixes #8373
2025-08-25 09:06:29 -05:00
Volodymyr Chernetskyi
5c03ff8165 i18n: update Ukrainian translation 2025-08-24 22:58:10 +02:00
trag1c
400576f0b0 i18n: Add missing ca_ES translations (#8371)
Part of #8344
2025-08-24 19:52:08 +02:00
KristoferSoler
c9199f2ba2 i18n: Add missing ca_ES translations
Part of #8344
2025-08-24 19:32:59 +02:00
trag1c
48120f8b6c fix: update Spanish translations and revision date in es_BO.UTF-8.po (#8374)
8 new strings added
2025-08-24 17:05:13 +02:00
Mitchell Hashimoto
27ed58252d Close other tabs feature on Mac. (#8363)
Supporting command line, file menu and keybindings. Default mac shortcut
of `super + alt + o` (other)

Not able to test on Linux so excluding `close_other_tabs` from `gtk` for
now
2025-08-24 08:00:11 -07:00
jamylak
c26323d697 Close other tabs feature on Mac.
Supporting command line, file menu and keybindings.
Default mac shortcut of `super + alt + o` (other)

Not able to test on Linux so excluding `close_other_tabs` from `gtk` for now
make a default short cut for close other tabs
2025-08-24 07:55:08 -07:00
Mitchell Hashimoto
13425b4881 Update iTerm2 colorschemes (#8368)
Upstream revision:
e4c0090a65
2025-08-24 07:02:50 -07:00
Mitchell Hashimoto
9ff716642e nix: update zon2nix (#8370)
- Builds with Zig 0.15 now (but still works just fine with Zig 0.14
projects).
- Fixes a double-free if nix-prefetch-git can't be found or errors out
- Adds support for generating Flatpak package metadata natively.
2025-08-24 07:02:38 -07:00
MiguelElGallo
c57a84a6de fix: update Spanish translations for window split terminology 2025-08-24 16:26:41 +03:00
MiguelElGallo
42b1ff70d1 fix: update Spanish translations and revision date in es_BO.UTF-8.po 2025-08-24 15:52:13 +03:00
Balázs Szücs
95bc181c98 Add hu_HU for Hungarian locale (#7560)
## Description of changes

Added Hungarian locale files, and corresponding translation

For the translation I mainly relied on my native skills, double checked
my work using LLMs.

Copilot generated summary:

This pull request introduces Hungarian language support to the
application by adding translations and updating the locale
configurations. The most important changes include the addition of
Hungarian translations in the `.po` file and registering the new locale
in the application's supported locales.

### Hungarian Language Support:

* Added Hungarian translations for various UI elements and messages in
the `po/hu_HU.UTF-8.po` file. This includes translations for prompts,
dialogs, menus, and other interface components.
* Updated the supported locales list in `src/os/i18n.zig` to include
`hu_HU.UTF-8`, enabling Hungarian as an available language option.

## Picture(s) of the translation


![image](https://github.com/user-attachments/assets/60f47f11-d55e-4408-889b-5b44ecaffc23)
2025-08-24 09:10:21 +00:00
Jeffrey C. Ollie
a18332828a nix: update zon2nix
- Builds with Zig 0.15 now (but still works just fine with Zig
  0.14 projects).
- Fixes a double-free if nix-prefetch-git can't be found or errors out
- Adds support for generating Flatpak package metadata natively.
2025-08-23 21:31:00 -05:00
mitchellh
00e4a90699 deps: Update iTerm2 color schemes 2025-08-24 00:14:50 +00:00
Mitchell Hashimoto
7622d2662d feat: add option to disable the "Reloaded the configuration" notification (#8366)
Redo of #8085 since I can't push that branch.
2025-08-23 12:59:09 -07:00
Mitchell Hashimoto
e1d4c37996 apprt/gtk-ng: some style changes for toast 2025-08-23 12:51:52 -07:00
dy0gu
1b8dd234b0 Merge branch 'main' of https://github.com/Elyptica/ghostty 2025-08-23 12:50:53 -07:00
dy0gu
43e010bf47 feat: add option to disable the "Reloaded the configuration" notification 2025-08-23 12:50:53 -07:00
Mitchell Hashimoto
062d596c0a terminal: fix use-after-free in exec (#8358)
This was only an issue on Linux, as MacOS' command is reallocated and
rewritten. We hit this using embedded Ghostty w/o a login shell :p
2025-08-23 12:45:44 -07:00
Kirwiisp
a3be474d28 add new translations 2025-08-23 21:03:25 +02:00
trag1c
b347585e27 i18n: update norwegian translations (#8365)
Updated the norwegian translation file to include the new translations
(cc @Uzaaft).
2025-08-23 19:37:15 +02:00
hanna
1aa59cf63d i18n: update choice selection prompt text 2025-08-23 13:19:13 -04:00
hanna
bd4e9b96bf i18n: update translation metadata 2025-08-23 12:53:05 -04:00
trag1c
59fd366264 i18n: Update Turkish translations (#8350)
Part of #8344
2025-08-23 18:48:35 +02:00
hanna
78f05ec96c i18n: adjust wording in translation 2025-08-23 12:48:32 -04:00
trag1c
0d536d447c i18n: Update Hebrew translation (#8362)
issue: #8344
2025-08-23 18:47:56 +02:00
hanna
4f4c06967a i18n: update norwegian translations 2025-08-23 12:43:02 -04:00
Emir SARI
f6f2a85256 i18n: Update Turkish translations
Signed-off-by: Emir SARI <emir_sari@icloud.com>
2025-08-23 19:27:19 +03:00
Gal
c181fc4fbf i18n: Update Hebrew translation
issue: #8344
2025-08-23 13:53:29 +03:00
Cheru Berhanu
d854ecd374 terminal: test execCommand w/ freed config 2025-08-22 15:55:08 -07:00
Cheru Berhanu
652f6f1deb terminal: fix use-after-free in exec
This was only an issue on Linux, as MacOS' command is reallocated and
rewritten. We hit this using embedded Ghostty w/o a login shell :p
2025-08-22 15:22:54 -07:00
Mitchell Hashimoto
c014dd79f6 terminal: fix build with -Di18n=false (#8359)
canonicalizeLocale should return a null-terminated string, and didn't
previously.

Compiler output:
```
src/os/i18n.zig:139:45: error: expected type 'error{NoSpaceLeft}![:0]const u8', found '[]const u8'
    if (comptime !build_config.i18n) return locale;
                                            ^~~~~~
src/os/i18n.zig:139:45: note: destination pointer requires '0' sentinel
src/os/i18n.zig:138:21: note: function return type declared here
) error{NoSpaceLeft}![:0]const u8 {
  ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
```
2025-08-22 14:54:11 -07:00
Cheru Berhanu
292efec669 terminal: fix build with -Di18n=false
canonicalizeLocale should return a null-terminated string, and didn't previously.

Compiler output:
```
src/os/i18n.zig:139:45: error: expected type 'error{NoSpaceLeft}![:0]const u8', found '[]const u8'
    if (comptime !build_config.i18n) return locale;
                                            ^~~~~~
src/os/i18n.zig:139:45: note: destination pointer requires '0' sentinel
src/os/i18n.zig:138:21: note: function return type declared here
) error{NoSpaceLeft}![:0]const u8 {
  ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
```
2025-08-22 14:47:04 -07:00
Mitchell Hashimoto
0c722b0e3d macos: if parent window is fullscreen, new window is fullscreen too (#8355)
Fixes #8229

This was a regression. 

The discussion noted in #8229 requests we create a new window on the
non-fullscreen desktop but that isn't how Ghostty has behaved
historically. I bisected back and tried 1.1.3 as well and we always
created a new fullscreen window when the parent was fullscreen.

This behavior matches iTerm2. Its noteworthy that native tabbing and
Apple apps such as Terminal.app and Safari do NOT do this. For both of
these, new window creates a _tab_ when in fullscreen. I don't think
that's particularly desirable, though.
2025-08-22 14:41:00 -07:00
Mitchell Hashimoto
54f8dff308 macos: if parent window is fullscreen, new window is fullscreen too
Fixes #8229

This was a regression. 

The discussion noted in #8229 requests we create a new window on the 
non-fullscreen desktop but that isn't how Ghostty has behaved
historically. I bisected back and tried 1.1.3 as well and we always
created a new fullscreen window when the parent was fullscreen.

This behavior matches iTerm2. Its noteworthy that native tabbing and
Apple apps such as Terminal.app and Safari do NOT do this. For both of
these, new window creates a _tab_ when in fullscreen. I don't think
that's particularly desirable, though.
2025-08-22 14:31:50 -07:00
Mitchell Hashimoto
60e077b651 deps: update z2d to v0.7.2 (#8354)
Release notes at:
  https://github.com/vancluever/z2d/blob/v0.7.2/CHANGELOG.md

This is mostly a bugfix release for text rendering, including a fix for
an invalid free flagged as:

https://github.com/vancluever/z2d/security/advisories/GHSA-v7f4-f3hm-282w

Note that the invalid free affects the new in-library text rendering
only and as such is likely not in use in Ghostty.

I'm anticipating *maybe* one more release after this ahead of Ghostty
1.2.0, depending on if I find any more bugs, but close to around the
release I am planning a freeze to ensure a clean versioned release
continues to be set.
2025-08-22 10:51:26 -07:00
Chris Marchesi
50fe12e85c deps: update z2d to v0.7.2
Release notes at:
  https://github.com/vancluever/z2d/blob/v0.7.2/CHANGELOG.md

This is mostly a bugfix release for text rendering, including a fix for
an invalid free flagged as:
  https://github.com/vancluever/z2d/security/advisories/GHSA-v7f4-f3hm-282w

Note that the invalid free affects the new in-library text rendering
only and as such is likely not in use in Ghostty.

I'm anticipating *maybe* one more release after this ahead of Ghostty
1.2.0, depending on if I find any more bugs, but close to around the
release I am planning a freeze to ensure a clean versioned release
continues to be set.
2025-08-22 10:30:01 -07:00
Mitchell Hashimoto
f4abecefe4 core: avoid possible deadlock in right-click-action paste actions (#8352)
Fixes #8313

The clipboard request flow can result in the apprt immediately
completing the request which itself grabs a lock. For pastes, we should
yield the lock during the clipboard request.

GTK is always async so this worked there, but we want to be resilient to
any apprt behavior here.
2025-08-22 09:52:51 -07:00
Mitchell Hashimoto
db60e981d1 core: avoid possible deadlock in right-click-action paste actions
Fixes #8313

The clipboard request flow can result in the apprt immediately
completing the request which itself grabs a lock. For pastes, we should
yield the lock during the clipboard request.

GTK is always async so this worked there, but we want to be resilient to
any apprt behavior here.
2025-08-22 09:49:18 -07:00
Mitchell Hashimoto
3859f50b88 Work around strange SwiftUI behavior in "older" macOSen. (might fix #7690) (#8026)
The Quick Terminal would not appear anymore, as somewhere in the
framework the Quick Terminal Window's geometry gets corrupted when the
window is added to the UI.

This works around by caching the windows geometry and reusing it
afterwards

This might fix #7690
2025-08-22 09:31:11 -07:00
Tobias Pape
4fdf0b687e typo found typos, typo may keep them 2025-08-22 09:19:25 -07:00
Tobias Pape
85cba70c2e Work around strange SwiftUI behavior in "older" macOSen.
The Quick Terminal would not appear anymore, as somewhere
in the framework the Quick Terminal Window's geometry
gets corrupted when the window is added to the UI.

This works around by caching the windows geometry and
reusing it afterwards
2025-08-22 09:17:49 -07:00
Mitchell Hashimoto
5bff354e96 fix: copy_url_to_clipboard copies full OSC8 URL instead of single cha… (#7551)
fix: copy_url_to_clipboard for OSC8 hyperlinks

OSC8 links were only detected when exact platform-specific modifiers
were held (Cmd on macOS, Ctrl on Linux), but copy_url_to_clipboard
should work with either. Additionally, OSC8 links were using
selectionString() which gets visible text instead of the actual URI. Now
we use osc8URI() for OSC8 links and fall back to selectionString() for
regex-detected links.

Fixes #7499
2025-08-22 09:14:36 -07:00
Mitchell Hashimoto
6d9cac5ffc macOS: order out alert sheets to avoid Stage Manager focus loss (#8348)
On macOS, when using stage manager, ghostty loses focus when a running
process is terminated.

This aims to fix #8336 which has reappeared since the previously fixed
#5108.

Opened a new pr following the closure of the previous #8343
2025-08-22 09:12:01 -07:00
Alex
6248030426 removed boolean logic, reverted back to ctrlOrSuper call 2025-08-22 09:10:53 -07:00
Alex
6708229a7e Removed boolean logic, reverted back to ctrlOrSuper call 2025-08-22 09:09:06 -07:00
Alex
91f973afdb Merge branch 'fix-copy-url' into fix-copy-url-minimal
Remove boolean logic as it is not needed, revert back to using ctrlOrSuper call in linkAtPos
2025-08-22 09:09:06 -07:00
Alex Straight
14f5a879a9 fix: make regular URLs work with either ctrl or super modifiers 2025-08-22 09:09:06 -07:00
Alex
eaa81be051 Merge branch 'main' into fix-copy-url 2025-08-22 09:09:06 -07:00
Alex
83b573aed7 remove commented out block 2025-08-22 09:09:06 -07:00
Alex
c78fb0f895 Removed boolean logic, reverted back to ctrlOrSuper call 2025-08-22 09:09:06 -07:00
Alex
5441578f08 Merge branch 'main' into fix-copy-url 2025-08-22 09:09:06 -07:00
Alex
c142473405 Merge branch 'main' into fix-copy-url
Merging main into fix-copy-url
2025-08-22 09:09:06 -07:00
Alex Straight
fc1307e939 fix: make regular URLs work with either ctrl or super modifiers 2025-08-22 09:09:06 -07:00
Alex Straight
5836dc4ce6 fix: copy_url_to_clipboard copies full OSC8 URL instead of single character
OSC8 links were only detected when exact platform-specific modifiers were held (Cmd on macOS, Ctrl on Linux), but copy_url_to_clipboard should work with either. Additionally, OSC8 links were using selectionString() which gets visible text instead of the actual URI. Now we use osc8URI() for OSC8 links and fall back to selectionString() for regex-detected links.

Fixes #7491
2025-08-22 09:09:06 -07:00
Alex Straight
93c2400bf4 fix: copy_url_to_clipboard copies full OSC8 URL instead of single character
OSC8 links were only detected when exact platform-specific modifiers were held (Cmd on macOS, Ctrl on Linux), but copy_url_to_clipboard should work with either. Additionally, OSC8 links were using selectionString() which gets visible text instead of the actual URI. Now we use osc8URI() for OSC8 links and fall back to selectionString() for regex-detected links.

Fixes #7491
2025-08-22 09:09:05 -07:00
Moeeze Hassan
f4009721a1 macOS: order out alert sheets to avoid Stage Manager focus loss
Signed-off-by: Moeeze Hassan <fammas.maz@gmail.com>
2025-08-22 09:05:20 -07:00
Alan Moyano
a479c9b2af i18n: add missing es_AR translations (#8347)
Part of #8344
2025-08-22 15:59:04 +02:00
Aindriú Mac Giolla Eoin
35102ddb5a Updating Irish translation for Ghostty 1.2 2025-08-22 14:53:56 +01:00
Mitchell Hashimoto
298f11166d macos: move activation to after new window/tab is created (#8338)
This is a follow-up to #8064, moving the activation into the async block
such that it happens after the window is created. As discussed in #8064,
this is necessary to bring only the newly created window to the front,
rather than both the previous main window and the new window.

Also made the same change for the new tab action, which also needs to
activate in case it was triggered from the dock menu or a global
keybind.

Finally, I removed the activations within AppDelegate that are redundant
now that TerminalController itself takes care of activating.
2025-08-21 15:38:40 -07:00
Daniel Wennberg
7d60c7c75b macos: move activation to after new window/tab is created 2025-08-21 15:16:20 -07:00
Mitchell Hashimoto
056ccc9818 macOS: update sparkle (#8337)
There aren't any noteworthy changes here we're just using a very old
version. Additionally, our CI was using... different versions!
2025-08-21 14:56:50 -07:00
Mitchell Hashimoto
3ef6de4ffa macos: in new_window action, activate App (#8064)
> [!NOTE]  
> The change might have been intentional, and so I lack context. I
mention two ways to fix below, this PR implements the first possible
fix.

This change makes sure that the new window is focused and visible.

When commit 33d128bcff removed the
TerminalManager class and moved its functionality into
TerminalController, it accidentally removed app activation for windows
triggered by global keybinds.

How the bug works:

1. Menu actions (like File → New Window) call AppDelegate.newWindow()
which: 2. Calls TerminalController.newWindow() 3. AND explicitly calls
NSApp.activate(ignoringOtherApps: true) in the AppDelegate
4. Global keybind actions trigger ghosttyNewWindow() notification
handler which:
      5. Only calls TerminalController.newWindow()
      6. Does NOT call NSApp.activate(ignoringOtherApps: true)
7. While TerminalController.newWindow() does call
NSApp.activate(ignoringOtherApps: true) internally, this call happens
before the async dispatch that shows the window, so the activation
occurs but the window isn't focused when it's actually shown.
8. In the old TerminalManager.newWindow(), the activation happened
immediately before the async dispatch, ensuring proper timing for window
focus.

To see the bug in action:
- run recent Ghostty `main`
- set up a global keybind for `new_window`
- focus some other window
- trigger keybind
- notice that Ghostty doesn't come to the foreground, but when manually
switching to Ghostty you will see that the new window _was_ created

The fix would be to either move the NSApp.activate() call back into
TerminalController.newWindow(), as it was for TerminalManager, or add
the activation call to the notification handlers in AppDelegate.
2025-08-21 14:09:44 -07:00
Mitchell Hashimoto
1ce56a12fa update sparkle
There aren't any noteworthy changes here we're just using a very old
version. Additionally, our CI was using... different versions!
2025-08-21 14:08:32 -07:00
Aljoscha Krettek
f736ee8865 macos: in new_window action, activate App
This change makes sure that the new window is focused and visible.

When commit 33d128bcff removed the
TerminalManager class and moved its functionality into
TerminalController, it accidentally removed app activation for windows
triggered by global keybinds.

How the bug works:

   1. Menu actions (like File → New Window) call AppDelegate.newWindow()
      which:
      2. Calls TerminalController.newWindow()
      3. AND explicitly calls NSApp.activate(ignoringOtherApps: true) in
         the AppDelegate
   4. Global keybind actions trigger ghosttyNewWindow() notification
      handler which:
      5. Only calls TerminalController.newWindow()
      6. Does NOT call NSApp.activate(ignoringOtherApps: true)
   7. While TerminalController.newWindow() does call
      NSApp.activate(ignoringOtherApps: true) internally, this call
      happens before the async dispatch that shows the window, so the
      activation occurs but the window isn't focused when it's actually
      shown.
   8. In the old TerminalManager.newWindow(), the activation happened
      immediately before the async dispatch, ensuring proper timing for
      window focus.

The fix would be to either move the NSApp.activate() call back into
TerminalController.newWindow(), as it was for TerminalManager, or add
the activation call to the notification handlers in AppDelegate.
2025-08-21 14:03:00 -07:00
Mitchell Hashimoto
40105e1c7e cli: add filtering hotkey to list_themes (#8082)
## Summary

Implements the theme filtering hotkey as requested in #7930. 

## Implementation

- Adds 'f' hotkey to cycle through filtering options: all, dark, and
light.
- Integrates with existing search functionality.
- Preserves CLI `--color` flag behavior for initial state.
- Updates help menu with the new hotkey. 

**NOTE**: I noticed another PR
[#8079](https://github.com/ghostty-org/ghostty/pull/8079) opened. I
started this implementation independently prior and don't want to step
on any toes. Happy to collaborate or defer to maintainers.
2025-08-21 14:01:50 -07:00
Mitchell Hashimoto
c110c0f76d gtk-ng: add a helper to reduce boilerplate in GTK IPC (#8306) 2025-08-21 13:34:53 -07:00
Mitchell Hashimoto
c675896595 ci: add 30 minute timeout to valgrind (#8333)
It usually takes less than a few minutes right now. Something is wrong
if it takes more than that.
2025-08-21 11:46:07 -07:00
Mitchell Hashimoto
53c2f915d8 gtk-ng: allow XKB remaps for non-writing-system keys (#8330)
Compromise solution to #7356

XKB is naughty. It's really really naughty. I don't understand why we
didn't just kill XKB with hammers during the Wayland migration and
change it for something much better. I don't understand why we're
content with what amounts to an OS-level software key remapper that
completely jumbles information about original physical key codes in
order to fake keyboard layouts, and not just let users who really want
to remap keys use some sort of evdev or udev-based mapper program.

In a sane system like macOS, the "c" key is always the "c" key, but it's
understood to produce the Unicode character "ц" when using a Russian
layout. XKB defies sanity, and just pretends that your "c" key is
actually a "ц" key instead, and so when you ask for the keybind "Ctrl+C"
it just shrugs in apathy (#7309). And so, we took matters into our own
hands and interpreted hardware keycodes ourselves.

But then, a *lot* of people have the ingrained muscle memory of swapping
Escape with Caps Lock so that it is easier to hit. We respect that. In a
sane system, they would use a remapper that actually makes the system
think you've hit the Escape key when in reality you've hit the Caps Lock
key, so in all intents and purposes to the OS and any app developer,
these two just have their wires swapped. But not on Linux. Somehow this
and the aforementioned case should be treated by the same key transform
algorithm, which is completely diabolical.

As a result, we have to settle for a compromise that truly satisfies
neither party — by allowing XKB remaps for keys that don't really change
depending on the layout.

The Linux input stack besets all hopes and aspirations.
2025-08-21 11:45:48 -07:00
Mitchell Hashimoto
795c745491 ci: add 30 minute timeout to valgrind
It usually takes less than a few minutes right now. Something is wrong
if it takes more than that.
2025-08-21 11:44:58 -07:00
Leah Amelia Chen
534aa508d6 gtk-ng: allow XKB remaps for non-writing-system keys
Compromise solution to #7356

XKB is naughty. It's really really naughty. I don't understand why we
didn't just kill XKB with hammers during the Wayland migration and change
it for something much better. I don't understand why we're content with
what amounts to an OS-level software key remapper that completely jumbles
information about original physical key codes in order to fake keyboard
layouts, and not just let users who really want to remap keys use some
sort of evdev or udev-based mapper program.

In a sane system like macOS, the "c" key is always the "c" key, but it's
understood to produce the Unicode character "ц" when using a Russian
layout. XKB defies sanity, and just pretends that your "c" key is
actually a "ц" key instead, and so when you ask for the keybind "Ctrl+C"
it just shrugs in apathy (#7309). And so, we took matters into our own
hands and interpreted hardware keycodes ourselves.

But then, a *lot* of people have the ingrained muscle memory of swapping
Escape with Caps Lock so that it is easier to hit. We respect that.
In a sane system, they would use a remapper that actually makes the
system think you've hit the Escape key when in reality you've hit the
Caps Lock key, so in all intents and purposes to the OS and any app
developer, these two just have their wires swapped. But not on Linux.
Somehow this and the aforementioned case should be treated by the same
key transform algorithm, which is completely diabolical.

As a result, we have to settle for a compromise that truly satisfies
neither party — by allowing XKB remaps for keys that don't really change
depending on the layout.

The Linux input stack besets all hopes and aspirations.
2025-08-22 02:02:11 +08:00
Mitchell Hashimoto
d725f2346f macOS: Add macos-dock-drop-folder-behavior (new tab or window) configuration option (#8114)
This PR adds a new configuration option
`macos-dock-drop-folder-behavior` that controls whether folders dropped
onto the Ghostty dock icon open in a new tab (default) or a new window.

## Changes

### Configuration Option Added
- **Option name**: `macos-dock-drop-folder-behavior`
- **Valid values**: 
  - `tab` (default) - Opens folders in a new tab in the main window
  - `window` - Opens folders in a new window
- **Platform**: macOS only

### Files Modified

1. **`src/config/Config.zig`**
- Added `MacOSDockDropFolderBehavior` enum with `tab` and `window`
values
   - Added configuration field with default value of `.tab`
   - Added documentation explaining the option

2. **`macos/Sources/Ghostty/Package.swift`**
   - Added `MacOSDockDropFolderBehavior` enum to match the Zig enum

3. **`macos/Sources/Ghostty/Ghostty.Config.swift`**
- Added `macosDockDropFolderBehavior` computed property to access the
configuration value from Swift

4. **`macos/Sources/App/macOS/AppDelegate.swift`**
- Modified `application(_:openFile:)` method to check the configuration
- When a folder is dropped on the dock icon, it now respects the user's
preference

## Usage

Add to your Ghostty configuration file:
```
macos-dock-drop-folder-behavior = window
```

## Motivation

This feature is useful for users (like me!) who prefer window-based
workflows over tab-based workflows when opening folders via drag and
drop on macOS.
2025-08-21 10:55:04 -07:00
Jeffrey C. Ollie
dcc5aded6e gtk-ng: more complete GTK startup/shutdown in test (#8324) 2025-08-21 12:52:10 -05:00
Mitchell Hashimoto
e01ff4093a macos: have macos-dock-drop-behavior apply to all drops 2025-08-21 10:45:17 -07:00
David Keegan
f9ad061ea8 Add macos-dock-drop-folder-behavior configuration option
This adds a new configuration option that controls whether folders
dropped onto the Ghostty dock icon open in a new tab (default) or
a new window.

The option accepts two values:
- tab: Opens folders in a new tab in the main window (default)
- window: Opens folders in a new window

This is useful for users who prefer window-based workflows over
tab-based workflows when opening folders via drag and drop.
2025-08-21 10:30:26 -07:00
Mitchell Hashimoto
d20376c1ff macOS Custom Icon + Persistence (#8230)
This PR aims to improve custom icons on macOS in the following ways. (I
based this PR on the discussion #3631)

### Currently
- Current Icon customizations are not persistent *(when closing the
application the icon in dock reverts back to official icon)*
- There is no officially supported way to change icon to be something
completely custom.

### After this PR
- Current icon customizations are persistent (closing the application no
longer reverts back to official icon)
- Ghostty config `macos-icon` has a new option `custom` which by default
looks for icon `~/.config/ghostty/Ghostty.icns`. It has an accompanying
new configuration `macos-custom-icon` which allows for a different path
to be specified, it does support more than just `.icns` as well.

Both changes are based on the thread with @sfsam in
https://github.com/ghostty-org/ghostty/discussions/3631#discussioncomment-12180647

Feedback is always welcome, if I have not done something up to par
please let me know and I will do my best to correct it.

NOTE: I did notice some newlines with indents which seems to be against
convention in those files so I removed the whitespace if this is not
preferred I can revert.

---

P.S. Thanks for all the work you put into making an awesome terminal!
2025-08-21 10:13:38 -07:00
ClearAspect
f7994e6412 fix: correct the cursor Y position value exposed to shader uniforms
Fix for discussion #8113

The cursor Y position value exposed to the shader uniforms was
incorrectly calculated. As per the doc in cell_text.v.glsl: In order to
get the top left of the glyph, we compute an offset based on the
bearings. The Y bearing is the distance from the bottom of the cell to
the top of the glyph, so we subtract it from the cell height to get the
y offset.

This calculation was mistakenly left out of the original code.

This will ensure that the custom shaders using
iCurrentCursor/iPreviousCursor get the correct Y coordinate representing
the top-left corner of the cursor rectangle, matching the documented
uniform behavior
2025-08-21 10:08:49 -07:00
Mitchell Hashimoto
f178f4419e macos: fix iOS builds 2025-08-21 10:03:25 -07:00
Nicholas Mata
f1c68f698b Correct Swift formatting inconsistencies 2025-08-21 10:00:15 -07:00
Nicholas Mata
5948bd3f02 Add support for 'custom' on 'macos_icon' to support a completely custom app icon 2025-08-21 10:00:15 -07:00
Nicholas Mata
29419e7aac Make macos icon persistent even when app is closed 2025-08-21 10:00:15 -07:00
Mitchell Hashimoto
66e5081721 ci: add timeout to snap and windows jobs (#8329)
There have been times these runaway taking forever for unknown reasons.
2025-08-21 09:29:44 -07:00
Mitchell Hashimoto
e92fe9d9f8 ci: add timeout to snap and windows jobs
There have been times these runaway taking forever for unknown reasons.
2025-08-21 09:22:14 -07:00
Mitchell Hashimoto
e3e69269e5 Switch macOS builds to Tahoe (Beta 7 currently) (#8328)
This switches our macOS builds to build on Tahoe, rather than on
Sequoia.

The primary motivation is to get builds out using a new Xcode version
(our builds at the time of writing this are _still produced_ with beta
1! ONE!). Every subsequent beta has had bugs that have prevented us from
upgrading, amusingly enough. But the later betas _also_ have a bunch of
fixes I want to get in. I hope this one works...

The reason we have to use Tahoe instead of Sequoia is because on
Sequoia, builds in CI _crash xcodebuild_. This is definitely an Apple
bug but I can't reproduce it locally to create a bug report, so I'm not
sure what to do.
2025-08-21 09:19:53 -07:00
Mitchell Hashimoto
82f7cd2133 ci: switch release builds to tahoe builders 2025-08-21 09:05:34 -07:00
Mitchell Hashimoto
7bb493e6ac ci: switch to Tahoe for builds 2025-08-21 07:36:59 -07:00
Mitchell Hashimoto
073a8b01d2 terminal: explicitly initialize undefined fields at runtime (#8323)
This works around the Zig issue as noted in the comment.

No new Valgrind issues found from this.
2025-08-21 07:34:21 -07:00
Jeffrey C. Ollie
36f7e018ae gtk-ng: more complete GTK startup/shutdown 2025-08-21 09:29:22 -05:00
Mitchell Hashimoto
531924e7e7 terminal: explicitly initialize undefined fields at runtime
This works around the Zig issue as noted in the comment.

No new Valgrind issues found from this.
2025-08-21 07:27:43 -07:00
Mitchell Hashimoto
2ffc61d21e gtk-ng: properly skip Zig test (#8322) 2025-08-21 07:25:30 -07:00
Jeffrey C. Ollie
2d0f930e6a gtk-ng: properly skip Zig test 2025-08-21 09:14:06 -05:00
Mitchell Hashimoto
7a42c82d18 temp: try downloading metal explicitly 2025-08-21 07:06:40 -07:00
Mitchell Hashimoto
d66747407d ci: move to bleedging edge sequoia builds
This will bring in Xcode 26 Beta 4 which I believe fixes all the known
issue we were dealing with keeping us on beta 1.
2025-08-21 07:06:40 -07:00
Mitchell Hashimoto
0e81f8d4e2 flatpak: manually install Zig 0.14.1 (#8311)
The SDK published on Flathub updated to Zig 0.15.1 which broke the
Flathub build in CI. So let's install it ourselves so that we can
control the version.
2025-08-21 07:04:50 -07:00
Mitchell Hashimoto
4cc33b546c Full unit test suite passing Valgrind (#8319)
This contains the various changes necessary to get the full unit test
suite passing Valgrind, and configures CI to run this.

I disabled relatively few (less than 10) tests under Valgrind because
they're way too slow: all `verifyIntegrity` tests, because those run
anyways in debug and check their own memory health, a font test that
fills out font map, and the sprite render test. Everything else runs
as-is.

I found a number of issues, most were in the tests themselves. A couple
in actual code. A funny one was some undefined memory on tabstop resize
if you exceed the default number of tabstops. I don't know any real
world program that ever even did that (memory issue aside), and that
whole file hasn't been touched since 2022, so that was funny.

No memory leaks in actual code, but a number of leaks in tests. All
resolved.

I think we're still missing some reports because of the Zig bug:
https://github.com/ziglang/zig/issues/19148 so I'm gong to audit our
codebase after this and look for cases of that.
2025-08-21 07:04:13 -07:00
Mitchell Hashimoto
793e817d74 ci: run all valgrind tests 2025-08-21 06:58:08 -07:00
Mitchell Hashimoto
96a0b9021c font: disable sprite test in valgrind 2025-08-21 06:57:25 -07:00
Mitchell Hashimoto
fe5eafac0a font: fix fontconfig leaks in unit tests 2025-08-21 06:53:59 -07:00
Jeffrey C. Ollie
6427a21679 flatpack: add back to list of required CI jobs 2025-08-21 00:42:18 -05:00
Qwerasd
d2ac29c919 font/CoreText: fix positioning for padded scaled glyphs (#8310)
When constraints increased or decreased the size significantly, the
fractional position was getting messed up by the scale. This change
separates that out so that it applies correctly.

I noticed this when messing around with constraints, adding this
constraint to every glyph and then running with `font-family=Arial` and
`adjust-cell-width = -35%` (if you want to reproduce this)
```zig
constraint = .{
    .size_horizontal = .stretch,
    .align_horizontal = .center,
    .pad_left = 0.1,
    .pad_right = 0.1,
};
```
The padding was disproportionately affecting thin glyphs that were
stretched a lot. The problem was that the padding was being multiplied
by the scale.

This also made it so the top or right of said thin glyphs often got
clipped off by the edge of the canvas.

Anyway I fixed it.

|Before|After|
|-|-|
|<img width="1824" height="1480" alt="image"
src="https://github.com/user-attachments/assets/32779f9d-a048-4a8c-b5ea-0e8a851d5119"
/>|<img width="1824" height="1480" alt="image"
src="https://github.com/user-attachments/assets/5bf449e5-699e-4bdc-ac96-2b776f9fb7fa"
/>|
2025-08-20 21:55:51 -06:00
Mitchell Hashimoto
a57afd41ac terminal: fix undefined memory access in unit test 2025-08-20 20:54:29 -07:00
Mitchell Hashimoto
566062c0a5 terminal: fix undefined memory in Tabstops code 2025-08-20 20:44:35 -07:00
Mitchell Hashimoto
be51f3e729 terminal: fix uninitialized memory in Cell init 2025-08-20 20:21:26 -07:00
Mitchell Hashimoto
3ce043123b terminal: fix undefined memory access in PageList eraseRows 2025-08-20 19:53:33 -07:00
Mitchell Hashimoto
2cebc225c0 ci: failing pagelist tests
on purpose, so we can verify CI fails
2025-08-20 19:46:37 -07:00
Jeffrey C. Ollie
1f7f678745 flatpak: manually install Zig 0.14.1
The SDK published on Flathub updated to Zig 0.15.1 which broke the
Flathub build in CI. So let's install it ourselves so that we can
control the version.
2025-08-20 19:10:25 -05:00
Qwerasd
610ce94f2d font/CoreText: fix positioning for padded scaled glyphs
When constraints increased or decreased the size significantly, the
fractional position was getting messed up by the scale. This change
separates that out so that it applies correctly.
2025-08-20 15:26:16 -06:00
Mitchell Hashimoto
4fa7b412d4 terminal: disable integrity checks under Valgrind 2025-08-20 14:05:31 -07:00
Mitchell Hashimoto
fec0defd04 ci: run valgrind in CI (#8309)
This runs Valgrind on our unit test suite in CI. Since we're not
currently passing Valgrind, this will be incrementally updated with the
filters for our passing tests. Ultimately, we'll remove the filters and
run the full suite.

Valgrind is slow and hungry so this is our first and only job currently
on a large instance.
2025-08-20 13:30:09 -07:00
Mitchell Hashimoto
5287b963c9 ci: run valgrind in CI
This runs Valgrind on our unit test suite in CI. Since we're not
currently passing Valgrind, this will be incrementally updated with the
filters for our passing tests. Ultimately, we'll remove the filters and
run the full suite.

Valgrind is slow and hungry so this is our first and only job currently
on a large instance.
2025-08-20 13:25:30 -07:00
Mitchell Hashimoto
f1300ec44f terminal: fix undefined memory access in OSC parser (#8307)
Fixes #8007

Verified with `test-valgrind -Dtest-filter="OSC"` which had cond access
errors before, and none after this. Basically a copy of #8008.
2025-08-20 13:15:40 -07:00
Mitchell Hashimoto
42f0c05d7e terminal: fix undefined memory access in OSC parser
Fixes #8007

Verified with `test-valgrind -Dtest-filter="OSC"` which had cond access
errors before, and none after this. Basically a copy of #8008.
2025-08-20 13:05:57 -07:00
Jeffrey C. Ollie
108260100c gtk-ng: add a helper to reduce boilerplate in GTK IPC 2025-08-20 14:53:17 -05:00
Mitchell Hashimoto
6aac8bfc24 terminal: change OSC parser to explicit init to set undefined (#8304)
This works around: https://github.com/ziglang/zig/issues/19148 This lets
our `test-valgrind` command catch some issues. We'll have to follow this
pattern in more places but I want to do it incrementally so things keep
passing.

I **do not** want to blindly follow this pattern everywhere. I want to
start by focusing in only on the structs that set `undefined` as default
fields that we're also about to test in isolation with Valgrind. It's
just too much noise otherwise and not a general style I'm sure of; it's
worth it for Valgrind though.

I'm making this PR separate from any fixes because the diff is so noisy
I don't want to lose the fixes in the noise. **This PR is therefore
functionally a no-op.**
2025-08-20 12:42:46 -07:00
Mitchell Hashimoto
131f170f89 terminal: change OSC parser to explicit init to set undefined
This works around: https://github.com/ziglang/zig/issues/19148
This lets our `test-valgrind` command catch some issues. We'll have to
follow this pattern in more places but I want to do it incrementally so
things keep passing.

I **do not** want to blindly follow this pattern everywhere. I want to
start by focusing in only on the structs that set `undefined` as default
fields that we're also about to test in isolation with Valgrind. Its
just too much noise otherwise and not a general style I'm sure of; it's
worth it for Valgrind though.
2025-08-20 12:38:29 -07:00
Mitchell Hashimoto
b3a80f2e47 build: add run-valgrind and test-valgrind steps (#8302)
This adds two explicit `zig build` steps: `run-valgrind` and
`test-valgrind` to run the Ghostty exe or tests under Valgrind,
respectively.

This simplifies the manual Valgrind calls in a few ways:

1. It automatically sets the CPU to baseline, which is a frequent and
requirement for Valgrind on newer CPUs, and generally safe.

2. It sets up the rather complicated set of flags to call Valgrind with,
importantly setting up our suppressions.

3. It enables pairing it with the typical and comfortable workflow of
specifying extra args (with `--`) or flags like `-Dtest-filter` for
tests.
2025-08-20 12:27:35 -07:00
Mitchell Hashimoto
f87213c2f6 build: add run-valgrind and test-valgrind steps
This adds two explicit `zig build` steps: `run-valgrind` and
`test-valgrind` to run the Ghostty exe or tests under Valgrind,
respectively.

This simplifies the manual Valgrind calls in a few ways:

1. It automatically sets the CPU to baseline, which is a frequent and
   requirement for Valgrind on newer CPUs, and generally safe.

2. It sets up the rather complicated set of flags to call Valgrind with,
   importantly setting up our suppressions.

3. It enables pairing it with the typical and comfortable workflow of
   specifying extra args (with `--`) or flags like `-Dtest-filter` for
   tests.
2025-08-20 11:43:48 -07:00
Jeffrey C. Ollie
a909aac252 contributing: add some notes about running valgrind (#8298) 2025-08-20 11:41:55 -05:00
Jeffrey C. Ollie
4171cd64e0 wuffs: simplify the build (#8299) 2025-08-20 11:37:51 -05:00
Jeffrey C. Ollie
3cce5d26d7 wuffs: simplify the build 2025-08-20 10:08:24 -05:00
Jeffrey C. Ollie
6032732001 contributing: add some notes about running valgrind 2025-08-20 09:03:48 -05:00
Mitchell Hashimoto
b52879b467 snap: remove workaround for build failures (#8292) 2025-08-19 20:35:35 -07:00
Jeffrey C. Ollie
aa26f8fd34 snap: remove workaround for build failures 2025-08-19 21:49:05 -05:00
Mitchell Hashimoto
e71c23802f AI tooling must be disclosed for contributions (#8289)
I think, at this stage of AI, it is a common courtesy to disclose this. 

In a perfect world, AI assistance would produce equal or higher quality
work than any human. That isn't the world we live in today, and in many
cases it's generating slop. I say this despite being a fan of and using
them successfully myself (with heavy supervision)! I think the major
issue is **inexperienced human drivers of AI** that aren't able to
**adequately review their generated code.** As a result, they're pull
requesting code that I'm sure they would be ashamed of if they knew how
bad it was.

The disclosure is to help maintainers assess how much attention to give
a PR. While we aren't obligated to in any way, I try to assist
inexperienced contributors and coach them to the finish line, because
getting a PR accepted is an achievement to be proud of. But if it's just
an AI on the other side, I don't need to put in this effort, and it's
rude to trick me into doing so.

**I'm a fan of AI assistance and use AI tooling myself.** But, we need
to be responsible about what we're using it for and respectful to the
humans on the other side that may have to review or maintain this code.

(In the spirit of this PR... none of this PR was AI generated. lol.)
2025-08-19 15:52:24 -07:00
Mitchell Hashimoto
7022c79521 ci: workaround snap builder issues (#8290)
Workaround produced by Namespace support. Thanks!
2025-08-19 15:52:15 -07:00
Mitchell Hashimoto
b4833c83cc ci: workaround snap builder issues
Workaround produced by Namespace support. Thanks!
2025-08-19 15:29:06 -07:00
Mitchell Hashimoto
babe923c8c AI tooling must be disclosed for contributions 2025-08-19 15:02:31 -07:00
Mitchell Hashimoto
f0acd02558 macos: show copy menu item if selection start is outside viewport (#8288)
Fixes #8187

This properly handles the scenario with our `read_text` C API when the
selection start is outside the viewport. Previously we'd report null (no
text) which would cascade into things like the right click menu not
showing a copy option.
2025-08-19 14:30:06 -07:00
Mitchell Hashimoto
63ca777e0f macos: show the copy menu item if we have any text selected 2025-08-19 14:23:50 -07:00
Mitchell Hashimoto
1c96870c17 macos: show copy menu item if selection start is outside viewport
Fixes #8187

This properly handles the scenario with our `read_text` C API when the
selection start is outside the viewport. Previously we'd report null (no
text) which would cascade into things like the right click menu not
showing a copy option.
2025-08-19 14:10:51 -07:00
Mitchell Hashimoto
5745f5048c Configurable right click behavior (#8254)
This MR addresses #4404 following the approach suggested
[here](https://github.com/ghostty-org/ghostty/issues/4404#issuecomment-2708410143).
Implementing the behavior known e.g. from Putty or Windows Terminal.

The following configuration values for `right-click-action` are
provided:
* `context-menu` - Show the context menu.
* `paste` - Paste the contents of the clipboard.
* `copy` - Copy the selected text to the clipboard.
* `copy-and-paste` - Copy the selected text to the clipboard, paste if
nothing is selected.
*  `ignore` - Do nothing, ignore the right-click.

I followed #5935 for getting an idea on where to start. I hope this to
be a temporary solution until "bindable mouse bindings" are introduced.

This is my first time writing Zig code, so I am happy to incorporate any
feedback.

Thank you all very much for your work!
2025-08-19 13:21:12 -07:00
Mitchell Hashimoto
f2de485cae gtk-ng: attach surface size callbacks AFTER realize (#8287)
The `gdk.Surface` is only ever available *after* the window had been
first presented and mapped. Trying to get the surface during `init` like
what we had previously done will **always** return null.
2025-08-19 12:36:23 -07:00
Mitchell Hashimoto
33b1c969d7 Fix PageList Reflow OOM Conditions (#8277)
Previously, when encountering an OOM when copying graphemes, hyperlinks,
or styles to a new page during reflow, the attempted resolution was to
copy the current row in to a new page and continue on- which works in
99% of cases, but isn't sound, since it's possible for a single row to
exceed the capacity on any of these.

This led to rare but real crashes like #8009.

I've added tests that produce all of the failure conditions, and
resolved them by changing the strategy from making a new page to
increasing the capacity of the current one.

There should probably be some level of abstraction added around this,
since multiple places in the code now do this sort of thing- attempt to
add some managed memory to a page, adjusting their capacity upwards as
necessary. But for now, I kept it all inline here.
2025-08-19 12:30:53 -07:00
Luzian Bieri
54b7e1838c feat: add right-click action configuration 2025-08-19 21:29:52 +02:00
Leah Amelia Chen
7977b3695a gtk-ng: attach surface size callbacks AFTER realize
The `gdk.Surface` is only ever available *after* the window had been
first presented and mapped. Trying to get the surface during `init`
like what we had previously done will **always** return null.
2025-08-20 03:29:15 +08:00
Mitchell Hashimoto
b3f68f6653 gtk-ng: fix toggle_window_decoration (#8286)
When window-decoration=none, setting the window decoration to null would
just mean it would default to none again, creating a cycle of torment
none can break out of... that sounds a bit too dramatic doesn't it

Fixes #8274
2025-08-19 12:27:38 -07:00
Mitchell Hashimoto
b65b42a5fa zsh: minor shell integration improvements (#8281)
- test `setupZsh`
- clean up `_ghostty_file` in the early exit path
- improve some `.zshenv` comments
2025-08-19 12:07:24 -07:00
Mitchell Hashimoto
27c2babae1 config: fix accidental codeblock indents (#8284)
In our webgen we treat 4 consecutive spaces as a code block, which is
often triggered by mistake when a paragraph is encased within a list.

We should probably fix this more thoroughly at some point since I don't
think actual Markdown parsers have the same behavior, but for now we
just fall back to using 3-space indents.

As an example of this occurring on the tip website:
<img width="1177" height="1012" alt="paragraphs being erroneously turned
into code blocks"
src="https://github.com/user-attachments/assets/878a8c83-3e37-41b7-90d9-fbd5b692bf16"
/>
2025-08-19 12:06:44 -07:00
Leah Amelia Chen
f3d8aac1e9 gtk-ng: fix toggle_window_decoration
When window-decoration=none, setting the window decoration to null would
just mean it would default to none again, creating a cycle of torment
none can break out of... that sounds a bit too dramatic doesn't it

Fixes #8274
2025-08-20 03:06:12 +08:00
Leah Amelia Chen
2421132d80 config: fix accidental codeblock indents
In our webgen we treat 4 consecutive spaces as a code block, which is
often triggered by mistake when a paragraph is encased within a list.

We should probably fix this more thoroughly at some point since I don't
think actual Markdown parsers have the same behavior, but for now we
just fall back to using 3-space indents.
2025-08-20 02:37:38 +08:00
Jon Parise
8300512a91 zsh: clarify that an unset ZDOTDIR defaults to HOME
This fixes the incorrect comment and uses $HOME (rather than ~) to be a
little bit more explicit.

Also, our script is named ghostty-integration, not ghostty.zsh, so
update that part of the comment, too.
2025-08-19 10:41:47 -04:00
Jon Parise
e8a60a375c zsh: unset _ghostty_file in the early exit path
If we're running a too-old version of zsh, we exit early. This skipped
the _ghostty_file cleanup path below.
2025-08-19 10:36:26 -04:00
Jon Parise
f430c03ff3 zsh: add tests for setupZsh 2025-08-19 10:35:05 -04:00
Qwerasd
a53ec1e567 PageList: increase capacity for style OOM during reflow 2025-08-18 19:18:20 -06:00
Qwerasd
ac308b0418 test(PageList): add failing test for reflow style OOM 2025-08-18 19:18:20 -06:00
Qwerasd
15aa9df051 PageList: increase capacity for grapheme OOM during reflow 2025-08-18 18:49:33 -06:00
Qwerasd
3fcfc34ef7 test(PageList): add failing test for reflow grapheme OOM 2025-08-18 18:39:10 -06:00
Qwerasd
c105d70c73 PageList: increase capacity for hyperlink OOM during reflow
It's possible for the hyperlink or string capacity to be exceeded in a
single row, in which case it doesn't matter if we move the row to a new
page, it will still be a problem. This was causing actual crashes under
some circumstances.
2025-08-18 18:30:50 -06:00
Qwerasd
61fc290ad1 test(PageList): add failing test for reflow hyperlink OOM 2025-08-18 18:27:28 -06:00
Mitchell Hashimoto
6fdaf21b82 BitmapAllocator Fixes/Improvements (#8276)
Improves the bitmap allocator's handling of allocations that are 64
chunks or more.

Previously, an allocation of exactly 64 chunks could not be freed, it
slipped through a crack in the logic and caused `free` to do nothing.

Also, >64 chunk allocations no longer always start at bitmap starts,
they can now start partway through a bitmap. If this had been fixed
before, it would have exposed a memory corruption issue in `free`, since
freeing such an allocation with the old logic would have fully cleared
its starting bitmap regardless of the starting point.

Adds a bunch of tests to exercise edge cases for free.

I didn't benchmark these changes, but I have a feeling that if there's a
performance difference it will be an improvement, since `free` now marks
more efficiently I believe (it was doing one bit at a time before), and
`findFreeChunks` now uses `clz` and `ctz` (on inverted versions of the
bitmaps).

Also, looking more closely as I type this, the old logic in
`findFreeChunks` may have had a potential corruption issue as well,
which could have allowed >64 chunk allocations to overlap the starts of
following allocations. I guess we didn't see it in the wild because our
chunk sizes are chosen in a way which would generally avoid >64 chunk
allocations in the VAST majority of cases.
2025-08-18 17:17:56 -07:00
Qwerasd
6d7982c8ca bitmap_allocator: improve/fix free
This previously had logic in it that was very wrong and could lead to
memory corruption or a failure to properly mark data as freed.

Also introduces a bunch of tests for various edge case behavior.
2025-08-18 17:52:10 -06:00
Qwerasd
058a91d217 bitmap_allocator: improve findFreeChunks for spans >64
This allows them to be packed more efficiently, rather than always
starting at a bitmap start.
2025-08-18 17:39:46 -06:00
Mitchell Hashimoto
d8842b933b gtk-ng: use virtual methods to draw the inspector (#8237)
Insead of signals between the ImGui widget and the Inspector widget,
make the Inspector widget a subclass of the ImGui widget and use virtual
methods to handle setup and rendering of the Inspector.
2025-08-18 10:00:44 -07:00
Mitchell Hashimoto
675ba0e9b8 apprt/gtk-ng: defineVirtualMethod helper 2025-08-18 09:58:51 -07:00
Jeffrey C. Ollie
1693c9a2ac gtk-ng: add some better comments on why getClass works 2025-08-18 09:20:40 -07:00
Jeffrey C. Ollie
34d10db7ea gtk-ng: remove some woefully naive musings on GObject memory layout 2025-08-18 09:20:40 -07:00
Jeffrey C. Ollie
23b3adedc3 gtk-ng: remove signals from imgui_widget 2025-08-18 09:20:40 -07:00
Jeffrey C. Ollie
dd072d2e01 gtk-ng: add some initial notes on memory layout of GObjects 2025-08-18 09:20:40 -07:00
Jeffrey C. Ollie
f147a89b68 gtk-ng: use gitlab permalinks 2025-08-18 09:20:40 -07:00
Jeffrey C. Ollie
38e69b2e96 gtk-ng: use virtual methods to draw the inspector
Insead of signals between the ImGui widget and the Inspector widget,
make the Inspector widget a subclass of the ImGui widget and use virtual
methods to handle setup and rendering of the Inspector.
2025-08-18 09:20:40 -07:00
Mitchell Hashimoto
936577c581 Update iTerm2 colorschemes (#8259)
Upstream revision:
8b639f0c26
2025-08-18 09:15:47 -07:00
Leah Amelia Chen
0f7b559f0f gtk-ng: fix race condition when checking border bell feature (#8267) 2025-08-18 10:56:06 +08:00
Jeffrey C. Ollie
7f8d215955 gtk-ng: fix race condition when checking border bell feature
Fixes #8266

When a surface is first created, there's a race condition between when
the config is set on the surface and when the code to check if a border
should be drawn around the surface is run. Fix that by exiting early if
the bell isn't ringing, before we check to see if there's a config set
on the surface and issuing the warning message.
2025-08-17 21:32:39 -05:00
Mitchell Hashimoto
02a942cf72 deps: update z2d to 0.7.1 tagged release (#8265)
This release contains performance and memory use improvements.

Some of the sprite font test renders had to be updated due to very minor
differences in the anti-aliasing, since the default anti-aliasing method
in z2d has been changed to MSAA rather than SSAA.
2025-08-17 15:38:32 -07:00
Qwerasd
2a9ba56cdc deps: update z2d to 0.7.1 tagged release
This release contains performance and memory use improvements.

Some of the sprite font test renders had to be updated due to very minor
differences in the anti-aliasing, since the default anti-aliasing method
in z2d has been changed to MSAA rather than SSAA.
2025-08-17 14:00:20 -06:00
mitchellh
324d92ea31 deps: Update iTerm2 color schemes 2025-08-17 00:15:25 +00:00
Luzian Bieri
933543a0d2 refactor: extract clipboard setting logic into copySelectionToClipboards function 2025-08-15 23:20:43 +02:00
Qwerasd
11d56235f9 Fix use-after-free in font.Atlas.grow (#8249)
Grow needs to allocate and might fail midway. It tries to handle this
using "undo" pattern, and restoring old state on error. But this is
exactly what steps into UAF, as, on error, both errdefer and defer are
run, and the old data is freed.

Instead, use a more robust "reservation" pattern, where we first
fallibly resrve all the resources we need, without applying any changes,
and than do the actual change once we are sure that cannot fail.
2025-08-15 13:15:23 -06:00
Qwerasd
0d4e673366 font/Atlas: add test for OOM behavior of grow
Similar tests should be added throughout the codebase for any function
that's supposed to gracefully handle OOM conditions. This one was added
because grow previously had a use-after-free bug under OOM, which this
would have caught.
2025-08-15 12:49:09 -06:00
Qwerasd
37ebf212d5 font/Atlas: cleanup grow
Reordered to form a more logical sequence of steps, cleaned up and
clarified comments, fixed invalid `appendAssumeCapacity` call which
erroneously passed `alloc`, so this compiles again.
2025-08-15 12:26:01 -06:00
Leah Amelia Chen
4f3553af5b gtk-ng: set IM context's input-purpose as terminal (#8251) 2025-08-16 01:58:04 +08:00
Alex Kladov
4c4d3cfc3f fix UAF in grow
Grow needs to allocate and might fail midway. It tries to handle this
using "undo" pattern, and restoring old state on error. But this is
exactly what steps into UAF, as, on error, both errdefer and defer are
run, and the old data is freed.

Instead, use a more robust "reservation" pattern, where we first
fallibly resrve all the resources we need, without applying any changes,
and than do the actual change once we are sure that cannot fail.
2025-08-15 18:45:01 +01:00
Leah Amelia Chen
5d19b24776 gtk-ng: refactor CSD/SSD style class settings (#8250) 2025-08-16 01:39:24 +08:00
Leah Amelia Chen
ed603b07a5 gtk-ng: set IM context's input-purpose as terminal
See https://github.com/ghostty-org/ghostty/issues/7987#issuecomment-3187597026
2025-08-16 01:35:45 +08:00
Leah Amelia Chen
11ecb516d4 gtk-ng: refactor CSD/SSD style class settings
Fixes #8127
2025-08-16 01:19:18 +08:00
Mitchell Hashimoto
0930b2daff apprt/gtk-ng: actually handle color scheme events (#8248)
Fixes #8245

Verified behavior before and after, also tested under Valgrind (was
curious because of the config change).
2025-08-15 09:42:17 -07:00
Mitchell Hashimoto
4bcaac50f2 apprt/gtk-ng: actually handle color scheme events
Fixes #8245
2025-08-15 09:38:03 -07:00
Mitchell Hashimoto
ed9415c659 apprt/gtk-ng: respect window-inherit-working-directory=false (#8247)
Fixes #8244
2025-08-15 09:27:15 -07:00
Mitchell Hashimoto
997e013d7e apprt/gtk-ng: respect window-inherit-working-directory=false
Fixes #8244
2025-08-15 09:18:28 -07:00
Mitchell Hashimoto
5b4baee9fa renderer: don't assume non-zero sized grid (#8246)
Fixes #8243

This adds a check for a zero-sized grid in cursor-related functions.

As an alternate approach, I did look into simply skipping a bunch of
work on zero-sized grids, but that looked like a scarier change to make
now. That may be the better long-term solution but this was an easily
unit testable, focused fix on the crash to start.
2025-08-15 09:07:22 -07:00
Mitchell Hashimoto
30c95f3bbb ci: switch to debian 13 (#8238) 2025-08-15 09:01:44 -07:00
Mitchell Hashimoto
9ccc02b131 renderer: don't assume non-zero sized grid
Fixes #8243

This adds a check for a zero-sized grid in cursor-related functions.

As an alternate approach, I did look into simply skipping a bunch of
work on zero-sized grids, but that looked like a scarier change to make
now. That may be the better long-term solution but this was an easily
unit testable, focused fix on the crash to start.
2025-08-15 08:59:24 -07:00
Jeffrey C. Ollie
63869d8e37 ci: switch to debian 13 2025-08-14 22:42:26 -05:00
Mitchell Hashimoto
4e26bb65ae apprt/gtk-ng: implement maximize and fullscreen (#8236)
These fell through the cracks.
2025-08-14 15:06:50 -07:00
Mitchell Hashimoto
6b1dd3e441 apprt/gtk-ng: implement maximize and fullscreen
These fell through the cracks.
2025-08-14 15:01:03 -07:00
Mitchell Hashimoto
264dbf9e46 apprt: make gtk-ng the default apprt on Linux (#8235)
The journey to rewrite our legacy GTK backend to a full GObject-based
backend is complete! The full background and motivation can be found in
the original PR: #7961. ~75 PRs later, we've reached **full parity**
with the legacy GTK backend.

Throughout the process, we've tested every feature under Valgrind, and
this build is fully clean of memory leaks and undefined access. Its
impossible to test the existing GTK backend because its full of false
positives, but based on my experience working on `-ng`, I think its
impossible we got it right. This isn't a dig at any of our GTK subsystem
maintainers; I've simply found its very complicated to get all the
memory management behaviors right with GTK. There are subtle, easy to
miss, weakly documented things, such as [clearing weak refs on
dispose](7548dcfe63).[^1]
The point is, **gtk-ng is much higher quality than legacy.**

There is only regression we know of (#8208). I'm willing to swap the
default despite this because the improvements not just in memory safety
but also behavior: splits now support spatial navigation, better
equalization behavior, etc.

At this point, I think we should swap the default to see if we missed
anything else.

[^1]: This isn't a dig at Gnome developers either. Documenting these
details is hard, too.
2025-08-14 14:05:16 -07:00
Mitchell Hashimoto
a148adc5e4 apprt: make gtk-ng the default apprt on Linux 2025-08-14 12:43:15 -07:00
Mitchell Hashimoto
b7913f09ad gtk-ng: add a helper for creating GTK actions (#8228)
- Reduces boilerplate.
- Adds type safety.
- Adds comptime checks for action and group names which
  otherwise could cause panics at runtime.
2025-08-14 12:26:39 -07:00
Mitchell Hashimoto
4740242bb9 fix(renderer/generic): deinit render targets with framestate (#8234)
This was a memory leak under Metal, leaked 1 swapchain worth of targets
every time a surface was closed.

Under OpenGL I think it was all cleaned up when the GL context was
destroyed.
2025-08-14 11:52:48 -07:00
Qwerasd
add7f762a6 fix(renderer/generic): deinit render targets with framestate
This was a memory leak under Metal, leaked 1 swapchain worth of targets
every time a surface was closed.

Under OpenGL I think it was all cleaned up when the GL context was
destroyed.
2025-08-14 11:47:05 -06:00
Jeffrey C. Ollie
d251695fa2 gtk-ng: move actions helper to namespace 2025-08-14 12:23:14 -05:00
Jeffrey C. Ollie
0e3ec24d2c gtk-ng: use action helper in surface 2025-08-14 12:22:42 -05:00
Jeffrey C. Ollie
6b690e6b4e gtk-ng: use action helper in split-tree 2025-08-14 12:22:42 -05:00
Jeffrey C. Ollie
31c71c6c5a gtk-ng: use action helper in tab 2025-08-14 12:22:39 -05:00
Jeffrey C. Ollie
d66212dcce gtk-ng: use action helper in window 2025-08-14 12:21:52 -05:00
Jeffrey C. Ollie
a10b95f052 gtk-ng: use action helper in application 2025-08-14 12:21:51 -05:00
Jeffrey C. Ollie
96e252872f gtk-ng: add a helper for creating GTK actions
- Reduces boilerplate.
- Adds type safety.
- Adds comptime checks for action and group names which
  otherwise could cause panics at runtime.
2025-08-14 12:21:51 -05:00
Mitchell Hashimoto
000efba31c apprt/gtk-ng: clean up close handling of all types (#8233)
This cleans up our close handling of all types (surfaces, tabs,
windows). Surfaces no longer emit their scope; their scope is always
just the surface itself. For tab and window scope we use widget actions.

This makes `close_tab` work properly (previously broken).
2025-08-14 10:20:55 -07:00
Mitchell Hashimoto
83d1bdcfcb apprt/gtk-ng: clean up close handling of all types
This cleans up our close handling of all types (surfaces, tabs, windows).
Surfaces no longer emit their scope; their scope is always just the
surface itself. For tab and window scope we use widget actions.

This makes `close_tab` work properly (previously broken).
2025-08-14 10:07:28 -07:00
Mitchell Hashimoto
3eda14e2d6 gtk-ng: port the terminal inspector (#8212)
This is a (relatively) straightforward port of the terminal inspector
from the old GTK application runtime. It's split into three widgets. At
the lowest level is a widget designed for showing a generic Dear ImGui
application. Above that is a widget that embeds the ImGui widget and
plumbs it into the core Inspector. At the top is a custom Window widget
that embeds the Inspector widget.

And then there's all the plumbing necessary to hook everything into the
rest of Ghostty.

In theory this design _should_ allow showing the Inspector in a split or
a tab in the future, not just in a separate window. It should also make
it easier to display _other_ Dear ImGui applications if they are ever
needed.
2025-08-14 09:47:09 -07:00
Mitchell Hashimoto
68f337e398 apprt/gtk-ng: close inspector window when widget loses surface 2025-08-14 09:42:26 -07:00
Mitchell Hashimoto
7548dcfe63 apprt/gtk-ng: clear weakrefs on dispose 2025-08-14 09:31:14 -07:00
Mitchell Hashimoto
76d84ff35c valgrind supps 2025-08-14 09:27:14 -07:00
Mitchell Hashimoto
6280bd7a42 apprt/gtk-ng: far less control inspector complexity 2025-08-14 08:57:11 -07:00
Mitchell Hashimoto
3fc33089f3 apprt/gtk-ng: clean up a bunch of unused window stuff 2025-08-14 08:37:58 -07:00
Mitchell Hashimoto
48a65b05d0 apprt/gtk-ng: use a weak_ref on surface for inspector 2025-08-14 08:21:19 -07:00
Mitchell Hashimoto
43550c18c0 apprt/gtk-ng: imguiwidget uses signals instead of callbacks 2025-08-14 08:21:19 -07:00
Jeffrey C. Ollie
bd7177a924 gtk-ng: port the terminal inspector
This is a (relatively) straightforward port of the terminal inspector
from the old GTK application runtime. It's split into three widgets. At
the lowest level is a widget designed for showing a generic Dear ImGui
application. Above that is a widget that embeds the ImGui widget and
plumbs it into the core Inspector. At the top is a custom Window widget
that embeds the Inspector widget.

And then there's all the plumbing necessary to hook everything into the
rest of Ghostty.

In theory this design _should_ allow showing the Inspector in a split
or a tab in the future, not just in a separate window. It should also
make it easier to display _other_ Dear ImGui applications if they are
ever needed.
2025-08-14 08:21:19 -07:00
Mitchell Hashimoto
57f1033198 gtk-ng: parametrize the new-split action (#8225)
why four when one do trick
2025-08-14 08:19:18 -07:00
Leah Amelia Chen
0979e6d2e9 gtk-ng: parametrize the new-split action
why four when one do trick
2025-08-14 08:17:01 -07:00
Mitchell Hashimoto
b57f1815a4 apprt/gtk-ng: set cursor on Surface widget, not GL area (#8227)
This fixes `mouse-hide-while-typing`. Don't know why this worked before
(I tested it yesterday!) but stopped working today. But this now works,
and conceptually makes some sense.
2025-08-13 15:44:31 -07:00
Mitchell Hashimoto
997d38c362 apprt/gtk-ng: set cursor on Surface widget, not GL area
This fixes `mouse-hide-while-typing`. Don't know why this worked before
(I tested it yesterday!) but stopped working today. But this now works,
and conceptually makes some sense.
2025-08-13 15:21:08 -07:00
Leah Amelia Chen
92d6395a8d gtk-ng: show on-screen keyboard on LMB release (#8224) 2025-08-14 05:00:17 +08:00
Leah Amelia Chen
1b1264e592 gtk-ng: only show OSD when mouse event isn't consumed 2025-08-14 04:06:02 +08:00
Leah Amelia Chen
23048dbd33 gtk-ng: add show_on_screen_keyboard binding 2025-08-14 04:06:02 +08:00
Leah Amelia Chen
0d0d3118f4 gtk-ng: show on-screen keyboard on LMB release
This aligns with VTE behavior when the on-screen keyboard is enabled in
GNOME's accessibility settings.

Closes #7987
2025-08-14 03:08:34 +08:00
Mitchell Hashimoto
5e3bd92c57 apprt/gtk-ng: prompt surface title (#8223)
Straightforward port. A hell of a lot cleaner with `-ng`.
2025-08-13 10:53:12 -07:00
Mitchell Hashimoto
ad781ee9cd gtk-ng add border to bell features (#8222) 2025-08-13 10:52:56 -07:00
Mitchell Hashimoto
8edc041eaf apprt/gtk-ng: prompt surface title 2025-08-13 10:49:16 -07:00
Jeffrey C. Ollie
22fc90fd55 gtk-ng add border to bell features 2025-08-13 12:18:07 -05:00
Mitchell Hashimoto
a843929d5a apprt/gtk-ng: bell (#8221)
Supersedes #8129

This is a rewrite but I did take pieces of #8129. I dropped the new
feature that was mixed into the PR because I'm trying not to introduce
new features in `-ng` right now. Feel free to PR that separately
@jcollie. I also dropped some of the action group validation stuff which
admittedly would be nice, so also happy to add that.

A big change I made here is we don't need to expose `bell-features` from
surface, because we can use the relevant config that we have access to.
I passed the config as a closure parameter so it recomputes when config
changes, too.

I also fixed a bug I found where we'd lose computed titles on
non-focused tabs because `active-surface` would start returning null
(since none are focused there). We now fallback to the active surface
being the _last focused_ surface if no focused surface exists, which
matches the behavior we also have on macOS.
2025-08-13 09:29:21 -07:00
Mitchell Hashimoto
6de98eda04 apprt/gtk-ng: audio bell
Co-authored-by: Jeffrey C. Ollie <jcollie@dmacc.edu>
2025-08-13 09:22:51 -07:00
Mitchell Hashimoto
d8a309c734 apprt/gtk-ng: split tree active focus should be last focused fallback
Co-authored-by: Jeffrey C. Ollie <jcollie@dmacc.edu>
2025-08-13 09:22:49 -07:00
Mitchell Hashimoto
3680c8637e apprt/gtk-ng: tab attention for bell
Co-authored-by: Jeffrey C. Ollie <jcollie@dmacc.edu>
2025-08-13 09:22:45 -07:00
Mitchell Hashimoto
d37e3828a2 apprt/gtk-ng: win.ring-bell
Co-authored-by: Jeffrey C. Ollie <jcollie@dmacc.edu>
2025-08-13 09:22:39 -07:00
Mitchell Hashimoto
408ec24165 apprt/gtk-ng: hook up bell into title
Co-authored-by: Jeffrey C. Ollie <jcollie@dmacc.edu>
2025-08-13 09:22:35 -07:00
Mitchell Hashimoto
40427b06c7 apprt/gtk-ng: surface bell-ringing property
Co-authored-by: Jeffrey C. Ollie <jcollie@dmacc.edu>
2025-08-13 09:22:16 -07:00
Mitchell Hashimoto
f1d55468dd apprt/gtk-ng: tab tooltips, window-subtitle, split zoom title prefix (#8218)
This brings together all our title-related functionality (so far).

To make this all work, I heavily use (abuse?) blueprint bindings with
closures. Blueprint sets up property subscription for all closure
parameters and all properties in a chain (`a.b.c`). This makes for a
really long, deeply nested property access but it saves us literally
hundreds (at least 100) lines of `notify` signal subscription
boilerplate.

This also lets some of these properties be truly dynamic and avoid
simply copying around intermediate values up the widget tree.

Unfortunately Blueprint's auto-formatter won't let us split property
access or function parameters onto separate lines so we're going to have
some very, very long lines.
2025-08-13 06:18:52 -07:00
Mitchell Hashimoto
798e872f48 apprt/gtk-ng: split zoom title 2025-08-12 15:45:59 -07:00
Mitchell Hashimoto
12bc0d7b10 apprt/gtk-ng: window-subtitle 2025-08-12 15:23:47 -07:00
Mitchell Hashimoto
502040c86a apprt/gtk-ng: tab tooltips match our pwd 2025-08-12 15:02:23 -07:00
Mitchell Hashimoto
aa4cbf444b apprt/gtk-ng: forgot to register a prop 2025-08-12 13:45:33 -07:00
Mitchell Hashimoto
bede3d8011 apprt/gtk-ng: split zoom (#8217)
This makes `toggle_split_zoom` work via a new widget action
`split-tree.zoom`. The zoom state is tracked on the core `SplitTree`
data structure. Zoom state is propagated via a `is-zoomed` property on
the split tree in GTK.

I deferred the title changes since I can do that all at once with
subtitle and other things.
2025-08-12 13:43:44 -07:00
Mitchell Hashimoto
f130a724e5 apprt/gtk-ng: track is-zoomed property on surface tree 2025-08-12 13:39:38 -07:00
Mitchell Hashimoto
fb846b669c split_tree: convert Handle to enum 2025-08-12 13:34:35 -07:00
Mitchell Hashimoto
145d1c1739 split_tree: track zoomed state 2025-08-12 13:08:04 -07:00
Mitchell Hashimoto
dfabb8aa4f build(deps): bump actions/checkout from 4.2.2 to 5.0.0 (#8213)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2
to 5.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
<li>Prepare v5.0.0 release by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2238">actions/checkout#2238</a></li>
</ul>
<h2>⚠️ Minimum Compatible Runner Version</h2>
<p><strong>v2.327.1</strong><br />
<a
href="https://github.com/actions/runner/releases/tag/v2.327.1">Release
Notes</a></p>
<p>Make sure your runner is updated to this version or newer to use this
release.</p>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4...v5.0.0">https://github.com/actions/checkout/compare/v4...v5.0.0</a></p>
<h2>v4.3.0</h2>
<h2>What's Changed</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
<li>Prepare release v4.3.0 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2237">actions/checkout#2237</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/motss"><code>@​motss</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li><a href="https://github.com/mouismail"><code>@​mouismail</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li><a href="https://github.com/benwells"><code>@​benwells</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li><a href="https://github.com/nebuk89"><code>@​nebuk89</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li><a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v4...v4.3.0">https://github.com/actions/checkout/compare/v4...v4.3.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>V5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>V4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
<li>Pin actions/checkout's own workflows to a known, good, stable
version. by <a href="https://github.com/jww3"><code>@​jww3</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1776">actions/checkout#1776</a></li>
</ul>
<h2>v4.1.6</h2>
<ul>
<li>Check platform to set archive extension appropriately by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1732">actions/checkout#1732</a></li>
</ul>
<h2>v4.1.5</h2>
<ul>
<li>Update NPM dependencies by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1703">actions/checkout#1703</a></li>
<li>Bump github/codeql-action from 2 to 3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1694">actions/checkout#1694</a></li>
<li>Bump actions/setup-node from 1 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1696">actions/checkout#1696</a></li>
<li>Bump actions/upload-artifact from 2 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1695">actions/checkout#1695</a></li>
<li>README: Suggest <code>user.email</code> to be
<code>41898282+github-actions[bot]@users.noreply.github.com</code> by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1707">actions/checkout#1707</a></li>
</ul>
<h2>v4.1.4</h2>
<ul>
<li>Disable <code>extensions.worktreeConfig</code> when disabling
<code>sparse-checkout</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1692">actions/checkout#1692</a></li>
<li>Add dependabot config by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1688">actions/checkout#1688</a></li>
<li>Bump the minor-actions-dependencies group with 2 updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1693">actions/checkout#1693</a></li>
<li>Bump word-wrap from 1.2.3 to 1.2.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1643">actions/checkout#1643</a></li>
</ul>
<h2>v4.1.3</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="08c6903cd8"><code>08c6903</code></a>
Prepare v5.0.0 release (<a
href="https://redirect.github.com/actions/checkout/issues/2238">#2238</a>)</li>
<li><a
href="9f265659d3"><code>9f26565</code></a>
Update actions checkout to use node 24 (<a
href="https://redirect.github.com/actions/checkout/issues/2226">#2226</a>)</li>
<li><a
href="08eba0b27e"><code>08eba0b</code></a>
Prepare release v4.3.0 (<a
href="https://redirect.github.com/actions/checkout/issues/2237">#2237</a>)</li>
<li><a
href="631c7dc4f8"><code>631c7dc</code></a>
Update package dependencies (<a
href="https://redirect.github.com/actions/checkout/issues/2236">#2236</a>)</li>
<li><a
href="8edcb1bdb4"><code>8edcb1b</code></a>
Update CODEOWNERS for actions (<a
href="https://redirect.github.com/actions/checkout/issues/2224">#2224</a>)</li>
<li><a
href="09d2acae67"><code>09d2aca</code></a>
Update README.md (<a
href="https://redirect.github.com/actions/checkout/issues/2194">#2194</a>)</li>
<li><a
href="85e6279cec"><code>85e6279</code></a>
Adjust positioning of user email note and permissions heading (<a
href="https://redirect.github.com/actions/checkout/issues/2044">#2044</a>)</li>
<li><a
href="009b9ae9e4"><code>009b9ae</code></a>
Documentation update - add recommended permissions to Readme (<a
href="https://redirect.github.com/actions/checkout/issues/2043">#2043</a>)</li>
<li><a
href="cbb722410c"><code>cbb7224</code></a>
Update README.md (<a
href="https://redirect.github.com/actions/checkout/issues/1977">#1977</a>)</li>
<li><a
href="3b9b8c884f"><code>3b9b8c8</code></a>
docs: update README.md (<a
href="https://redirect.github.com/actions/checkout/issues/1971">#1971</a>)</li>
<li>See full diff in <a
href="11bd71901b...08c6903cd8">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=4.2.2&new-version=5.0.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-08-12 12:30:50 -07:00
Mitchell Hashimoto
7bcb190aa8 apprt/gtk-ng: resize_split action (#8215)
Ports the resize split action (tied to the `resize_split` binding
action).

This also includes fixes for splits that are exactly `0` or `1` ratio
width (full width either direction). This would previously cause
crashes.
2025-08-12 12:27:26 -07:00
Mitchell Hashimoto
93da59682f apprt/gtk-ng: resizeSplit action 2025-08-12 11:04:34 -07:00
Mitchell Hashimoto
4afd3445c4 split_tree: fix bugs for 0/1 sized ratios 2025-08-12 10:46:43 -07:00
dependabot[bot]
8d8812cb6a build(deps): bump actions/checkout from 4.2.2 to 5.0.0
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 5.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](11bd71901b...08c6903cd8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 08:52:43 +00:00
Mitchell Hashimoto
2bcc2fa4bd split_tree: resize function 2025-08-11 12:52:16 -07:00
Qwerasd
5bf632e9cc Fix up font raster position + other small fixes (#8206)
I've cleaned up the code we use for scaling and positioning glyphs for
raster, under both CoreText and FreeType. Before we had some
imprecision, and under CoreText we were sometimes stretching glyphs in
unseemly ways. These changes make it so that our constraints can
position and size glyphs *exactly* and we don't have any chopped-off
row/column issues for CoreText. With this, PowerLine Extra symbols now
always align *perfectly* with the cell height:
||Before|After|
|-:|-|-|
|**CoreText**|<img width="105" height="245" alt="image"
src="https://github.com/user-attachments/assets/d3c1b1cb-a798-4e18-a0e0-59551893369c"
/>|<img width="106" height="246" alt="image"
src="https://github.com/user-attachments/assets/dac10c49-9ec1-4f4f-8825-a5e8c2fd3402"
/>|
|**FreeType**|<img width="105" height="245" alt="image"
src="https://github.com/user-attachments/assets/160e1e35-4a3c-42d0-9042-215301e636a1"
/>|<img width="106" height="245" alt="image"
src="https://github.com/user-attachments/assets/89bf1538-7271-4baf-88c0-51ebc4d360df"
/>|

The other changes are mainly just cleanup stuff, though one of the
changes makes it so that we do once again properly apply constraints to
symbols from the dingbats block (it was a regression, noted in #7955,
that we stopped doing that).

### Future work
This has been a problem since we introduced the custom constraints, but
I noticed it while preparing the before/after images: the left-edge PLE
symbols (meant to connect to a full block on the right) expand out to
the *right*, so if they're followed immediately by another character
than they actually get squished and don't match the right-edge symbols:

<img width="75" height="114" alt="image"
src="https://github.com/user-attachments/assets/1420b9a5-9950-4210-9934-8ef7cd7a1e19"
/>

I have a WIP change to move constraint logic to the shapers, and at that
point we can maybe do something to allow the constraint to grow in to
whitespace on the left side instead of on the right side.
2025-08-11 13:44:50 -06:00
Mitchell Hashimoto
a94bd8f5c4 gtk-ng: don't use signals to toggle command palette (#8182) 2025-08-11 12:02:48 -07:00
Jeffrey C. Ollie
5bb88d259c gtk-ng: use WeakRef helper for type safety 2025-08-11 11:56:08 -07:00
Jeffrey C. Ollie
2de0c108ba gtk-ng: better handling of weak references
The upstream GIR for g_weak_ref_get is incorrect - it does not allow the
returned value to be NULL. This PR pulls in a new version of our GObject
bindings with that patched and improves the safety of dealing with the
command palette weak reference held by the window.

See ianprime0509/zig-gobject#117
2025-08-11 11:56:08 -07:00
Jeffrey C. Ollie
5c088d10a4 gtk-ng: fix memory leaks in command palette 2025-08-11 11:56:08 -07:00
Jeffrey C. Ollie
3221421a74 gtk-ng: add TODOs about passing surface that toggled command palette 2025-08-11 11:56:08 -07:00
Jeffrey C. Ollie
8af1230228 gtk-ng: don't add extra refs when activating a command in the palette 2025-08-11 11:56:08 -07:00
Jeffrey C. Ollie
2a5b7aab86 gtk-ng: don't use signals to toggle command palette 2025-08-11 11:56:08 -07:00
Mitchell Hashimoto
21a9760ff5 apprt/gtk-ng: equalize splits (#8211)
Fixes known issues from #8202. Also brings in the better equalization
logic on macOS from #7710.
2025-08-11 11:39:19 -07:00
Mitchell Hashimoto
9f037a7c23 apprt/gtk-ng: equalize splits 2025-08-11 11:35:13 -07:00
Mitchell Hashimoto
a21b447c75 apprt/gtk-ng: goto_split (including spatial navigation for the first time for our GTK backend) (#8210)
This continues #8202 by fixing two of the known issues: `goto_split` key
binds work and closing a split moves focus to the proper place.

A big improvement in this PR is that for the first time ever in our GTK
backend, the up/down/left/right `goto_split` bindings **use spatial
navigation.** "Spatial navigation" means that the direction to move
focus is done based on the nearest split _visually_ from the current
split, rather than via a tree traversal. We did this on macOS a couple
months ago, with a lot more details there: #7523

Similar to macOS, the spatial navigation is currently based on top-left
corner. Now that our split tree is implemented in Zig though it should
be a lot easier for us to work in the current cursor position as the
reference point.

~~🚧 TODO: Going to add some unit tests for the spatial navigation before
merge.~~
2025-08-11 11:04:06 -07:00
Mitchell Hashimoto
43c3150e81 split_tree: unit tests for spatial nav, fix a bug 2025-08-11 10:59:37 -07:00
Mitchell Hashimoto
5a01877c77 apprt/gtk-ng: spatial navigation 2025-08-11 10:17:13 -07:00
Mitchell Hashimoto
70d48d03a5 apprt/gtk-ng: go to right focus when split closes 2025-08-11 09:51:58 -07:00
Mitchell Hashimoto
5903d7d10f apprt/gtk-ng: hook up goto_split 2025-08-11 09:44:13 -07:00
Mitchell Hashimoto
984435d7ea split_tree: deepest, previous, next traversals 2025-08-11 09:30:59 -07:00
Mitchell Hashimoto
9f959ea876 gtk-ng: fix split-divider-color config (#8209) 2025-08-11 08:38:28 -07:00
Jeffrey C. Ollie
b726183981 gtk-ng: fix split-divider-color config 2025-08-11 10:28:54 -05:00
Mitchell Hashimoto
a9a41aec83 apprt/gtk-ng: create/close split functionality (#8202)
This adds on to our existing foundations from #8165 and adds the ability
to create and close splits. We're still missing split navigation,
resizing via keybindings, etc. And there are a number of known issues
(listed below). But this is a strict improvement from where we're at and
includes a number of important bug fixes to our split tree.

The only nasty thing in this PR is that I learned that GTK _did not
like_ rebuilding our split widget tree on every data model change. I
don't know enough about how all the re-parenting plus size allocation
interactions work together. As a compromise, this PR adds a listener,
waits for our surface tree to "settle" by having all surfaces have no
parents, then schedules a single rebuild after that. This works well,
but results in some noticeable flashing for a frame or so. I think we
can improve this later, it works completely well enough.

Importantly, all of this is Valgrind clean. I long suspected our splits
on legacy are NOT free of leaks, but never proved it, so this makes me
happy.

## Demo



https://github.com/user-attachments/assets/e231d89f-581e-486b-ade0-1d7e6795262e



## Known Issues

I may fix this in this PR, I may follow up.

- [ ] Focus doesn't go to the right place after closing a split
- [x] Divider with a transparent background is transparent
- [x] Close split doesn't show any close confirmation dialog
- Missing features:
  * [ ] Equalize splits
  * [ ] Resize splits keybind (manual mouse action works fine)
  * [ ] Go to split keybind
2025-08-11 08:25:38 -07:00
Mitchell Hashimoto
edd73fa0e4 font/freetype: convert encoding of font names (#8204)
Freetype encodes some font names internally in formats other than UTF-8.
This only affects debug logs but it was annoying me so I fixed it. There
may be other encodings that might need to be dealt with but I took care
of the one that I ran across.
2025-08-10 19:55:35 -07:00
Mitchell Hashimoto
dd983d112d gtk-ng: sync action accelerators for split-tree (#8207) 2025-08-10 19:55:22 -07:00
Jeffrey C. Ollie
aba5a34335 gtk-ng: sync action accelerators for split-tree 2025-08-10 21:31:50 -05:00
Qwerasd
8c7538e996 font/freetype: port improved raster logic from CoreText
We now also have absolute perfect control over the raster position under
FreeType as well. This means that, for example, powerline extended chars
are appropriately clamped to the cell edges at all sizes.

This should be purely an improvement over what we had before, and now it
also matches what we do for CoreText.
2025-08-10 19:59:52 -06:00
Jeffrey C. Ollie
e9e32d71e4 font/freetype: add a test for face name decoding using embedded fonts 2025-08-10 20:10:24 -05:00
Jeffrey C. Ollie
897d70982e font/freetype: convert encoding of font names
Freetype encodes some font names internally in formats other than UTF-8.
This only affects debug logs but it was annoying me so I fixed it. There
may be other encodings that might need to be dealt with but I took care
of the one that I ran across.
2025-08-10 17:29:31 -05:00
Qwerasd
5383cd9c9c font/freetype: pass monochrome load flag when needed
The monochrome hinter is very aggressive but makes text actually look
tolerable when rendered in monochrome. If for some god forsaken reason
we get complaints about this, that someone wanted improperly hinted mono
glyphs, we can introduce additonal configuration; but for now, this is
just a straight improvement.
2025-08-10 16:04:54 -06:00
Qwerasd
20a9a3a8c2 font: use adjusted cell width for recentering again
The old method was nice, but had an issue that's intractible without
significant reworking in how we do shaping: combining glyphs need to
position relative to the glyph they're combining with, but if we re-
center that glyph, it will be off by some amount.
2025-08-10 15:49:54 -06:00
Qwerasd
195cbb6a1c Revert "font/Metrics: remove original_cell_width, no longer needed"
This reverts commit 23cc50b12c.
2025-08-10 15:33:47 -06:00
Qwerasd
f56219be95 font/coretext: fix glyph position/scale code
Apologies to Apple, the previous comments in this section of the code
were not correct-- `shouldSubpixelQuantizeFonts` does pretty much what
the minimal documentation for it says it does, it simply quantizes the
position of the glyph and nothing more. Various bugs when testing while
writing the old code that led me to include those comments made me not
realize that the positioning is actually a lot simpler than it seems.

With this version of the positioning there are never any cut-off rows or
columns of pixels on the edges of anything and everything scales as it
should... I hope. I checked pretty thoroughly this time and I'm like 99%
sure this is correct in all cases.
2025-08-10 15:11:20 -06:00
Qwerasd
ee445d2915 font: compare font Index packed structs directly
Packed structs can be compared directly now, no need to convert them to
an int anymore.
2025-08-10 15:11:20 -06:00
Qwerasd
a8b9dd8dfc renderer: clean up, improve constraintWidth function 2025-08-10 14:54:51 -06:00
Mitchell Hashimoto
ca4e38ff03 apprt/gtk-ng: split close confirmation 2025-08-10 13:35:30 -07:00
Mitchell Hashimoto
441af8389b apprt/gtk-ng: split separator styling 2025-08-10 13:09:06 -07:00
Mitchell Hashimoto
0aaf80402b Update iTerm2 colorschemes (#8195)
Upstream revision:
3cbeca99ef
2025-08-10 12:52:48 -07:00
Mitchell Hashimoto
46560d0018 apprt/gtk-ng: wait for unparent to rebuild split tree 2025-08-10 12:36:28 -07:00
mitchellh
c64701e744 deps: Update iTerm2 color schemes 2025-08-10 00:15:37 +00:00
Mitchell Hashimoto
b1da644b62 apprt/gtk-ng: unnecessary grab focus 2025-08-09 14:48:42 -07:00
Mitchell Hashimoto
e682e99bf5 apprt/gtk-ng: hook up win split actions 2025-08-09 14:36:50 -07:00
Mitchell Hashimoto
aed6a3a343 apprt/gtk-ng: clean up some changed handlers 2025-08-09 14:24:25 -07:00
Mitchell Hashimoto
ec293c1fd0 apprt/gtk-ng: active surface hookups 2025-08-09 13:49:36 -07:00
Mitchell Hashimoto
8232cf33b4 apprt/gtk-ng: surface close in split tree 2025-08-09 12:36:27 -07:00
Mitchell Hashimoto
a28d673467 update supps 2025-08-09 12:24:40 -07:00
Mitchell Hashimoto
9ad92d2c3d apprt/gtk-ng: proper split operations 2025-08-09 12:21:28 -07:00
Mitchell Hashimoto
34be4de018 apprt/gtk-ng: write back split ratio to tree 2025-08-09 12:19:10 -07:00
Mitchell Hashimoto
e396d9d78d apprt/gtk-ng: setup gtk paned listeners to set position 2025-08-09 07:27:11 -07:00
Mitchell Hashimoto
a3c041bcb4 apprt/gtk-ng: keep track of last focused surface 2025-08-08 15:14:41 -07:00
Mitchell Hashimoto
517f17995c apprt/gtk-ng: rebuild the widget tree on an idle callback 2025-08-08 14:38:02 -07:00
Mitchell Hashimoto
fbe28477ff datastruct: fix split tree ascii diagram 2025-08-08 14:22:38 -07:00
Mitchell Hashimoto
75dd8e46b5 datastruct: fix split tree debug log rounding 2025-08-08 14:22:38 -07:00
Mitchell Hashimoto
ae5dc3a4fb apprt/gtk-ng: split tree new split actions 2025-08-08 14:22:38 -07:00
Mitchell Hashimoto
4742177daa apprt/gtk-ng: template callbacks can't return bool, must be c_int (#8186)
This fixes the tab bar showing the window controls sometimes.
2025-08-08 13:39:46 -07:00
Mitchell Hashimoto
5bf8f12cf0 apprt/gtk-ng: template callbacks can't return bool, must be c_int
This fixes the tab bar showing the window controls sometimes.
2025-08-08 13:36:08 -07:00
Mitchell Hashimoto
8ae72d5f7f apprt/gtk-ng: set resize overlay label in the idle callback (#8185)
This avoids jitter when resizing splits. I didn't see any jitter before
splits but conceptually its possible. The issue is that since we're
updating the overlay DURING A RESIZE, changing the dimensions of any
part of the widget tree causes GTK warnings and a bunch of laggy
updates.

Instead, we copy the label text to a property and update it on the idle
callback along with everything else. This also provides a natural
debounce to the label.
2025-08-08 13:14:13 -07:00
Mitchell Hashimoto
8e073505f7 apprt/gtk-ng: set resize overlay label in the idle callback
This avoids jitter when resizing splits. I didn't see any jitter before
splits but conceptually its possible. The issue is that since we're
updating the overlay DURING A RESIZE, changing the dimensions of any
part of the widget tree causes GTK warnings and a bunch of laggy
updates.

Instead, we copy the label text to a property and update it on the idle
callback along with everything else. This also provides a natural
debounce to the label.
2025-08-08 12:59:54 -07:00
Mitchell Hashimoto
729b8f9c2d apprt/gtk-ng: add proper setters for surface properties (#8184)
This also fixes a bug where we were setting custom cursors on the wrong
gtk widget, this showed up most terribly with `mouse-hide-while-typing`
where the mouse would never reappear.
2025-08-08 12:36:42 -07:00
Mitchell Hashimoto
17101294aa gtk-ng: add "title bar styles" (#8166)
This PR adds a "tabs" title bar style similar to the macOS title bar
style. When `gtk-titlebar-style=tabs` the title bar and the tab bar will
be merged together.

The config entry for controlling this is kept separate from macOS as
macOS has more styles defined that don't map to a GTK title bar style
and it's likely that users that use both macOS and GTK would want
different settings for each platform.

<img width="922" height="722" alt="Screenshot From 2025-08-06 16-38-28"
src="https://github.com/user-attachments/assets/3c2db235-695a-457e-9c96-5039120263fc"
/>
2025-08-08 12:34:21 -07:00
Mitchell Hashimoto
16e15554da apprt/gtk-ng: add proper setters for surface properties
This also fixes a bug where we were setting custom cursors on the wrong
gtk widget, this showed up most terribly with `mouse-hide-while-typing`
where the mouse would never reappear.
2025-08-08 12:30:22 -07:00
Jeffrey C. Ollie
cae60f7c29 gtk-ng: use single if expression instead of block 2025-08-08 13:36:45 -05:00
Jeffrey C. Ollie
0f67282dfa gtk-ng: add "title bar styles"
This PR adds a "tabs" title bar style similar to the macOS title bar
style. When `gtk-titlebar-style=tabs` the title bar and the tab bar
will be merged together.

The config entry for controlling this is kept separate from macOS as
macOS has more styles defined that don't map to a GTK title bar style
and it's likely that users that use both macOS and GTK would want
different settings for each platform.
2025-08-08 13:32:23 -05:00
Mitchell Hashimoto
2c0bb894b8 valgrind: GtkPopover suppressions (#8183)
We get a ton of leaks from GTK.PopOver when we run the steps given in
the suppression file. I don't see how this could be us since we don't
create or do anything with the popover manually; its simply defined in
the Blueprint file.

The leaks specifically only happen when a Popover shows a sub-menu.
Without that, everything is completely clean. So I actually suspect
there's some leaks in GTK related to this behavior (not sure if they're
on purpose not, a brief look at the code doesn't look like they're
reused).

I tried alternate approaches where we create the Popover AND/OR the
MenuModel in code without the Blueprint file and we get the same leaks.

I'm kind of suspicious about this one but don't see how we can do
anything about it, so I'm going to suppress for now. The suppression
file has detailed repro steps that people can use to hopefully test this
later.
2025-08-08 11:27:47 -07:00
Mitchell Hashimoto
17b4481767 fix: capture screenshot for app intents views as NSImage (#8180)
SwiftUI's ImageRenderer must not be called outside the main thread.

The `@MainActor` annotation is only relevant for our own code, not
for calls from frameworks. The machinations around Shortcuts end up
calling the displayRepresentation method outside the main thread.

By capturing the screenshot as NSImage, all data is retained and can
be processed outside the main thread.

Thread in Discord:
https://discord.com/channels/1005603569187160125/1403384231694172372
2025-08-08 10:25:56 -07:00
Mitchell Hashimoto
ef817cd267 valgrind: GtkPopover suppressions
We get a ton of leaks from GTK.PopOver when we run the steps given in
the suppression file. I don't see how this could be us since we don't
create or do anything with the popover manually; its simply defined in
the Blueprint file.
2025-08-08 10:16:02 -07:00
Alexander Lais
1f378e6775 fix: capture screenshot for app intents views as NSImage
SwiftUI's ImageRenderer must not be called outside the main thread.

The `@MainActor` annotation is only relevant for our own code, not
for calls from frameworks. The machinations around Shortcuts end up
calling the displayRepresentation method outside the main thread.

By capturing the screenshot as NSImage, all data is retained and can
be processed outside the main thread.
2025-08-08 16:53:26 +02:00
Mitchell Hashimoto
a0eb4285b2 build(deps): bump namespacelabs/nscloud-cache-action from 1.2.15 to 1.2.16 (#8175)
Bumps
[namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action)
from 1.2.15 to 1.2.16.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="305bfa7ea9"><code>305bfa7</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/31">#31</a>
from namespacelabs/niklas-new-pnpm</li>
<li><a
href="ca35d05e60"><code>ca35d05</code></a>
Do not touch node_modules in PNPM mode.</li>
<li>See full diff in <a
href="f2d0a9e9ed...305bfa7ea9">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.15&new-version=1.2.16)](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-08-08 07:03:15 -07:00
Leah Amelia Chen
4d9d133ebc inspector: fix display for fractional pixel sizes (#8179) 2025-08-08 17:12:43 +08:00
Leah Amelia Chen
7663f7d922 inspector: fix display for fractional pixel sizes
#4371 2: Electric Boogaloo

Regression caused by #7953
2025-08-08 14:39:26 +08:00
dependabot[bot]
23a6d4f276 build(deps): bump namespacelabs/nscloud-cache-action
Bumps [namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action) from 1.2.15 to 1.2.16.
- [Release notes](https://github.com/namespacelabs/nscloud-cache-action/releases)
- [Commits](f2d0a9e9ed...305bfa7ea9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-08 00:17:36 +00:00
Mitchell Hashimoto
c659f9c5d2 gtk-ng: nuke .nick and .blurb from property definitions (#8173) 2025-08-07 13:43:58 -07:00
Jeffrey C. Ollie
b5073b34ee gtk-ng: nuke .nick and .blurb from property definitions 2025-08-07 13:12:56 -05:00
Mitchell Hashimoto
4aa12b76e7 apprt/gtk-ng: split tree foundations (#8165)
This begins to bring back splits to `gtk-ng`. As of this PR, **splits
still don't work**, but the architectural underpinnings for them are all
present. Namely, our tab view now embeds a `GhosttySplitTree` widget
which has a full split tree present, and all the signals and active
surface properties and so on are hooked up to the tree.

In theory, once we hook up split creation, close, etc. everything should
_just work_.

But, this PR is already very large and I don't want to make it even
larger, so I'm opening this PR to add the foundations for this while
keeping `gtk-ng` in the state it more or less is on main right now.

The meat of this is in a pure Zig data structure `SplitTree` added to
`src/datastruct`. This is a Ziggified port of our macOS implementation
(but, much better if I do say so myself). Being in pure Zig lets us
write unit tests easily, control allocations tightly, get our safety
checks, etc. There is coverage in this PR.

## Other Bugs Fixed

- Boxed accessors use the proper `g_boxed_copy/free` functions. Didn't
really cause any issues because this is the first PR where we actually
use custom implementations for that.

- `Surface` properly emits a notify event for focus change
2025-08-07 08:41:18 -07:00
Mitchell Hashimoto
326e55c8f8 apprt/gtk-ng: PR feedback 2025-08-07 08:37:22 -07:00
Mitchell Hashimoto
4a4577cf8a apprt/gtk-ng: address some TODOs 2025-08-07 08:14:02 -07:00
Mitchell Hashimoto
bc731c0ff6 apprt/gtk-ng: hook up Tab signals to surface 2025-08-07 08:14:02 -07:00
Mitchell Hashimoto
3b4c33afe0 apprt/gtk-ng: connect surface signals 2025-08-07 08:14:02 -07:00
Mitchell Hashimoto
a7865d79ea apprt/gtk-ng: render a single artificial split 2025-08-07 08:14:02 -07:00
Mitchell Hashimoto
70b050ebb4 apprt/gtk-ng: setup split tree property 2025-08-07 08:14:02 -07:00
Mitchell Hashimoto
fa08434b28 apprt/gtk-ng: initial GhosttySplitTree widget 2025-08-07 08:14:02 -07:00
Mitchell Hashimoto
ad1cfe8347 remove outdated comment 2025-08-07 08:14:02 -07:00
Mitchell Hashimoto
3e767c166c datastruct: split tree node removal 2025-08-07 08:14:02 -07:00
Mitchell Hashimoto
52e264948d apprt/gtk-ng: ASCII output for SplitTree 2025-08-07 08:14:02 -07:00
Mitchell Hashimoto
5c30ac0e8e apprt/gtk-ng: spatial tree 2025-08-07 08:14:02 -07:00
Mitchell Hashimoto
7811c04f9d apprt/gtk-ng: SplitTree data structure 2025-08-07 08:14:02 -07:00
Mitchell Hashimoto
6238103f21 font: disable discretionary ligatures by default (#8164)
Closes #5372

Discretionary ligatures (denoted by the OpenType feature tag `dlig`) are
sometimes used by programming fonts (e.g. Iosevka) to provide more
"complex" and uncommon ligatures that may be useful in a programming
context. Unfortunately, this has some nasty side effects with certain
Japanese fallback fonts (#5372) due to perhaps a misaligned
understanding of the OpenType spec[^spec].

The spec details that `dlig` ligatures should only be used to contract
sequences of glyphs together into one glyph, and that it should be used
only for "special effect", **at the user's preference** (emphasis mine).
Indeed, it also suggests that:

> UI suggestion: This feature should be off by default.

All of this, combined with the fact that historical, nowadays unused and
even unintelligible Kanji ligatures are explicitly included as examples
of discretionary ligatures, shows that in the Japanese context at least
that the "level of discretion" is significantly higher than what is
found in programming fonts, where it is more understood to be
"opinionated and uncommon", rather than "obsolete and unreadable".

Furthermore, it appears that a lot of common programming fonts don't
even make use of the `dlig` feature — JetBrains Mono, FiraCode and
MonoLisa lack a `dlig` feature altogether, while Inconsolata seems to
only use it for ligatures that are more commonly found in `liga` or
`calt`, such as the `->` ligature. To a lot of people, then, this change
would literally alter nothing.

Therefore, it's my opinion that we should disable `dlig` by default.
It's arguably not being used correctly in the programming font space (or
at least not in a way that's coherent with other fonts), and it only
provides a marginal benefit while potentially rendering entire sentences
in Japanese (and possibly other languages) unreadable out of the box.

If someone upgrades to tip or 1.2 and then asks "why aren't the
ligatures working anymore", then at least they can always just turn on
`dlig` by themselves.

[^spec]:
https://learn.microsoft.com/en-us/typography/opentype/spec/features_ae#tag-dlig
2025-08-07 07:14:39 -07:00
Mitchell Hashimoto
1158419b7f build(deps): bump namespacelabs/nscloud-cache-action from 1.2.14 to 1.2.15 (#8167)
Bumps
[namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action)
from 1.2.14 to 1.2.15.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f2d0a9e9ed"><code>f2d0a9e</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/30">#30</a>
from namespacelabs/niklas-wipe-debug</li>
<li><a
href="c532e9b02c"><code>c532e9b</code></a>
Fix cache content test, and add debug outputs.</li>
<li>See full diff in <a
href="a2c6b4830e...f2d0a9e9ed">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.14&new-version=1.2.15)](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-08-07 07:12:27 -07:00
Mitchell Hashimoto
f0b1b0236c gtk/gtk-ng: update zig-gobject to pick up fix for ianprime0509/zig-gobject#115 (#8169) 2025-08-07 07:12:04 -07:00
Leah Amelia Chen
f107b2f910 font/{harfbuzz,coretext}: enable dlig for test shaper
Some of the tests rely on dlig and I'm far too lazy to rewrite those
tests now
2025-08-07 11:54:31 +08:00
Jeffrey C. Ollie
3b898a9800 gtk/gtk-ng: update zig-gobject to pick up fix for ianprime0509/zig-gobject#115 2025-08-06 21:19:18 -05:00
dependabot[bot]
8774e88d4e build(deps): bump namespacelabs/nscloud-cache-action
Bumps [namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action) from 1.2.14 to 1.2.15.
- [Release notes](https://github.com/namespacelabs/nscloud-cache-action/releases)
- [Commits](a2c6b4830e...f2d0a9e9ed)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-07 00:55:06 +00:00
Leah Amelia Chen
eb96ff0757 font: disable discretionary ligatures by default
Closes #5372

Discretionary ligatures (denoted by the OpenType feature tag `dlig`) are
sometimes used by programming fonts (e.g. Iosevka) to provide more
"complex" and uncommon ligatures that may be useful in a programming
context. Unfortunately, this has some nasty side effects with certain
Japanese fallback fonts (#5372) due to perhaps a misaligned understanding
of the OpenType spec[^spec].

The spec details that `dlig` ligatures should only be used to contract
sequences of glyphs together into one glyph, and that it should be used
only for "special effect", **at the user's preference** (emphasis mine).
Indeed, it also suggests that:

> UI suggestion: This feature should be off by default.

All of this, combined with the fact that historical, nowadays unused and
even unintelligible Kanji ligatures are explicitly included as examples
of discretionary ligatures, shows that in the Japanese context at least
that the "level of discretion" is significantly higher than what is found
in programming fonts, where it is more understood to be "opinionated and
uncommon", rather than "obsolete and unreadable".

Furthermore, it appears that a lot of common programming fonts don't even
make use of the `dlig` feature —  JetBrains Mono, FiraCode and MonoLisa
lack a `dlig` feature altogether, while Inconsolata seems to only use it
for ligatures that are more commonly found in `liga` or `calt`, such as
the `->` ligature. To a lot of people, then, this change would literally
alter nothing.

Therefore, it's my opinion that we should disable `dlig` by default.
It's arguably not being used correctly in the programming font space
(or at least not in a way that's coherent with other fonts), and it only
provides a marginal benefit while potentially rendering entire sentences
in Japanese (and possibly other languages) unreadable out of the box.

If someone upgrades to tip or 1.2 and then asks "why aren't the ligatures
working anymore", then at least they can always just turn on `dlig` by
themselves.

[^spec]: https://learn.microsoft.com/en-us/typography/opentype/spec/features_ae#tag-dlig
2025-08-07 03:33:24 +08:00
Leah Amelia Chen
1d042f1e71 build: allow disabling i18n (#8158) 2025-08-06 21:09:03 +08:00
Leah Amelia Chen
5fbdb8c459 build: allow disabling i18n
GNU gettext simply is a PITA on certain platforms (i.e. Windows, musl
Linux, etc.) and currently it's not possible to cleanly remove i18n
from the build process, making building Ghostty on the aforementioned
platforms difficult. By providing users with a way to opt-out of the
i18n mechanisms (or opt-in, on platforms where i18n is disabled by
default) we can make sure that people at least have *some* way of
building Ghostty before i18n mechanisms can be integrated neatly.
2025-08-06 14:54:02 +08:00
Mitchell Hashimoto
1ec8188b5c build(deps): bump actions/download-artifact from 4.3.0 to 5.0.0 (#8156)
Bumps
[actions/download-artifact](https://github.com/actions/download-artifact)
from 4.3.0 to 5.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/download-artifact/releases">actions/download-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/407">actions/download-artifact#407</a></li>
<li>BREAKING fix: inconsistent path behavior for single artifact
downloads by ID by <a
href="https://github.com/GrantBirki"><code>@​GrantBirki</code></a> in <a
href="https://redirect.github.com/actions/download-artifact/pull/416">actions/download-artifact#416</a></li>
</ul>
<h2>v5.0.0</h2>
<h3>🚨 Breaking Change</h3>
<p>This release fixes an inconsistency in path behavior for single
artifact downloads by ID. <strong>If you're downloading single artifacts
by ID, the output path may change.</strong></p>
<h4>What Changed</h4>
<p>Previously, <strong>single artifact downloads</strong> behaved
differently depending on how you specified the artifact:</p>
<ul>
<li><strong>By name</strong>: <code>name: my-artifact</code> → extracted
to <code>path/</code> (direct)</li>
<li><strong>By ID</strong>: <code>artifact-ids: 12345</code> → extracted
to <code>path/my-artifact/</code> (nested)</li>
</ul>
<p>Now both methods are consistent:</p>
<ul>
<li><strong>By name</strong>: <code>name: my-artifact</code> → extracted
to <code>path/</code> (unchanged)</li>
<li><strong>By ID</strong>: <code>artifact-ids: 12345</code> → extracted
to <code>path/</code> (fixed - now direct)</li>
</ul>
<h4>Migration Guide</h4>
<h5> No Action Needed If:</h5>
<ul>
<li>You download artifacts by <strong>name</strong></li>
<li>You download <strong>multiple</strong> artifacts by ID</li>
<li>You already use <code>merge-multiple: true</code> as a
workaround</li>
</ul>
<h5>⚠️ Action Required If:</h5>
<p>You download <strong>single artifacts by ID</strong> and your
workflows expect the nested directory structure.</p>
<p><strong>Before v5 (nested structure):</strong></p>
<pre lang="yaml"><code>- uses: actions/download-artifact@v4
  with:
    artifact-ids: 12345
    path: dist
# Files were in: dist/my-artifact/
</code></pre>
<blockquote>
<p>Where <code>my-artifact</code> is the name of the artifact you
previously uploaded</p>
</blockquote>
<p><strong>To maintain old behavior (if needed):</strong></p>
<pre lang="yaml"><code>&lt;/tr&gt;&lt;/table&gt; 
</code></pre>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="634f93cb29"><code>634f93c</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/416">#416</a>
from actions/single-artifact-id-download-path</li>
<li><a
href="b19ff43027"><code>b19ff43</code></a>
refactor: resolve download path correctly in artifact download tests
(mainly ...</li>
<li><a
href="e262cbee4a"><code>e262cbe</code></a>
bundle dist</li>
<li><a
href="bff23f9308"><code>bff23f9</code></a>
update docs</li>
<li><a
href="fff8c148a8"><code>fff8c14</code></a>
fix download path logic when downloading a single artifact by id</li>
<li><a
href="448e3f862a"><code>448e3f8</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/download-artifact/issues/407">#407</a>
from actions/nebuk89-patch-1</li>
<li><a
href="47225c44b3"><code>47225c4</code></a>
Update README.md</li>
<li>See full diff in <a
href="d3f86a106a...634f93cb29">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/download-artifact&package-manager=github_actions&previous-version=4.3.0&new-version=5.0.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-08-05 20:14:13 -07:00
Mitchell Hashimoto
1a74ce1b10 gtk-ng: a couple of minor fixes (#8157)
A couple of minor fixes that I found while exploring tonight:

- OSC 22 wasn't working on gtk-ng. Fixed by setting the cursor shape
directly on the surface.
- Removed use of deprecated property on GLArea
2025-08-05 20:13:56 -07:00
Jeffrey C. Ollie
35e3ac8b4c gtk-ng: remove use of deprecated use-es GLArea property 2025-08-05 19:56:00 -05:00
Jeffrey C. Ollie
288601e386 gtk-ng: fix OSC 22 not changing mouse shape on -ng 2025-08-05 19:56:00 -05:00
dependabot[bot]
7db2ab9863 build(deps): bump actions/download-artifact from 4.3.0 to 5.0.0
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.3.0 to 5.0.0.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](d3f86a106a...634f93cb29)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-06 00:29:00 +00:00
Kat
2b670a8e13 update Polish translations (#8151) 2025-08-05 23:49:29 +00:00
Mitchell Hashimoto
70ec59d566 macOS: properly handle buffer allocation in ZH locale canonicalization (#8137)
Fix a bug introduced by #6885 

`fixZhLocale` returns locale string literal without copying it into the
buffer, causing the `LANGUAGE` environment variable to be set
incorrectly.
```log
$ LANG="" zig build run
...
debug(os_locale): setting LANGUAGE from preferred languages value=�����.UTF-8:�����.UTF-8:en_US.UTF-8:ja_CN.UTF-8
...
```
2025-08-05 09:41:15 -07:00
Mitchell Hashimoto
5c0e15f50f gtk-ng: port the command palette (#8083) 2025-08-05 09:40:37 -07:00
Mitchell Hashimoto
19fde96d30 funny typos 2025-08-05 09:38:08 -07:00
Mitchell Hashimoto
8022539f82 gitignore: ignore core dumps created by valgrind (#8152) 2025-08-05 09:22:32 -07:00
Mitchell Hashimoto
10a7e39456 zig: switch all uses of callconv(.C) to callconv(.c) (#8153) 2025-08-05 09:14:52 -07:00
Jeffrey C. Ollie
cf77897388 gtk-ng: port the command palette 2025-08-05 10:33:08 -05:00
Jeffrey C. Ollie
6ae333869e zig: switch all uses of callconv(.C) to callconv(.c) 2025-08-05 10:32:03 -05:00
Jeffrey C. Ollie
a50605c5df gitignore: ignore core dumps created by valgrind 2025-08-05 10:24:58 -05:00
Aaron Ruan
c1060d56b3 macOS: properly handle buffer in zh locale canonicalization 2025-08-05 22:56:28 +08:00
trag1c
5cf5f71c72 update Polish translations 2025-08-05 16:29:08 +02:00
Mitchell Hashimoto
18c2ff561f build(deps): bump namespacelabs/nscloud-cache-action from 1.2.13 to 1.2.14 (#8148)
Bumps
[namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action)
from 1.2.13 to 1.2.14.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/namespacelabs/nscloud-cache-action/releases">namespacelabs/nscloud-cache-action's
releases</a>.</em></p>
<blockquote>
<h2>v1.2.14</h2>
<ul>
<li><a
href="93ab075400">Fix
post path cache summary and wipe non-cacheable contents in post
step.</a></li>
<li>[PNPM] <a
href="48cddb643a">Set
copy mode and avoid spurious warnings.</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a2c6b4830e"><code>a2c6b48</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/29">#29</a>
from namespacelabs/niklas-wipe</li>
<li><a
href="93ab075400"><code>93ab075</code></a>
Fix post path cache summary and wipe non-cacheable contents in post
step.</li>
<li><a
href="fa4ddeb1d7"><code>fa4ddeb</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/28">#28</a>
from namespacelabs/niklas-pnpm-copy</li>
<li><a
href="48cddb643a"><code>48cddb6</code></a>
Set copy mode and avoid spurious warnings.</li>
<li>See full diff in <a
href="9ff6d4004d...a2c6b4830e">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.13&new-version=1.2.14)](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-08-05 07:09:01 -07:00
dependabot[bot]
ce68a864f0 build(deps): bump namespacelabs/nscloud-cache-action
Bumps [namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action) from 1.2.13 to 1.2.14.
- [Release notes](https://github.com/namespacelabs/nscloud-cache-action/releases)
- [Commits](9ff6d4004d...a2c6b4830e)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-05 07:24:31 +00:00
Mitchell Hashimoto
37bac094c7 apprt/gtk-ng: action accelerators, clean up explicit error sets (#8146)
Not a lot here, ported the action accelerators which was small.

Besides that, cleaned up a bunch of explicit error sets which allowed us
to remove some forwarded errors because they're so unlikely, and could
unify others.
2025-08-04 12:45:06 -07:00
Mitchell Hashimoto
8c85bae931 apprt/gtk-ng: background-opacity doesn't need to be a window property
We only need properties for things that are bound via the blueprint
files. Otherwise, its kind of just a pain. This fixes a bug where it
wasn't being properly set initially anyways because we didn't trigger
syncAppearance.
2025-08-04 12:41:44 -07:00
Mitchell Hashimoto
55c68d809d apprt/gtk-ng: action accelerators, clean up explicit error sets 2025-08-04 12:35:37 -07:00
Mitchell Hashimoto
84cb4ce31a apprt/gtk-ng: surface context menu (#8144)
Port with changes:

* Utilizes the Surface blueprint for defining the `PopoverMenu`
* We can't attach it directly to the Overlay using blueprints because an
overlay can only have a single child property and you can't see other
children via Blueprint. To overcome this, use a `Box`
* Utilizing a `menu` signal the window can listen to to refresh its
action map instead of digging into ancestor hierarchy.
2025-08-04 11:43:17 -07:00
Mitchell Hashimoto
ee6d9b3116 apprt/gtk-ng: surface context menu 2025-08-04 11:28:48 -07:00
Mitchell Hashimoto
1d62f37cbb apprt/gtk-ng: global shortcuts (#8142)
Ports global shortcuts. 

This is mostly a direct logic copy. The primary difference is I
converted `GlobalShortcuts` to a `GObject` which has a config and dbus
property and emits a trigger signal. Importantly, it's no longer tied or
dependent on the `gio.Application` in any way. The config and dbus
connection are updated as normal properties.

Verified with Valgrind we're clean. Found one memory leak I ported back
to legacy.
2025-08-04 10:37:57 -07:00
Mitchell Hashimoto
c8fce8850b apprt/gtk-ng: global shortcuts 2025-08-04 10:25:24 -07:00
Mitchell Hashimoto
41e8f1374b gtk-ng: prevent split button from becoming focused (#8136)
Without this, if you create a new tab by clicking on the split button it
will be the focus for any new input. So for example if you create a new
tab and then immediately press the space bar a bunch of new tabs will be
created. Other keypresses will just "disappear". Only by clicking in the
new tab to focus it will keyboard input go to "the right place".
2025-08-04 08:07:52 -07:00
Jon Parise
eccff1ea95 fix fish shell syntax for ssh-env shell integration (#8138)
As discussed here
https://github.com/ghostty-org/ghostty/discussions/8021

This fixes invalid fish shell syntax.

As an example, run ghostty like so: `XDG_CONFIG_HOME=/tmp ghostty
--shell-integration-features=ssh-env --command="/usr/bin/env fish"`.
Setting `XDG_CONFIG_HOME` to `/tmp` is just to start from the default
configs for ghostty and fish.

Before:

```
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish
robbiev@neo ~/s/ghostty (fish-shell-ssh)> ssh git@github.com
env: ‘command’: No such file or directory
robbiev@neo ~/s/ghostty (fish-shell-ssh) [127]>
```

After:

```
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish
robbiev@neo ~/s/ghostty (fish-shell-ssh)> ssh git@github.com
PTY allocation request failed on channel 0
Hi robbiev! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.
robbiev@neo ~/s/ghostty (fish-shell-ssh) [1]>
```

(This fails correctly)

I've also tried with a correctly accessible ssh server but of course you
can't repro that easily if you don't have some place to ssh to.

```
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish
robbiev@neo ~/s/ghostty (fish-shell-ssh)> ssh trinity

[robbiev@trinity:~]$ echo $TERM
xterm-ghostty
```

My understanding of the fix follows.

The script is using `command` to make sure it calls the actual ssh
binary and not some intermediate shell function with the same name (`man
command` explains).

`env` can be useful for fish compat < 3.1, where [the KEY=value syntax
was
introduced](https://fishshell.com/docs/current/faq.html#how-do-i-set-or-clear-an-environment-variable).
However because `command` is a builtin it doesn't work in this case.

So a simple solution is this, requiring fish >= 3.1

```
TERM="$ssh_term" command ssh $ssh_opts $argv
```

An
[alternative](https://serverfault.com/questions/164305/how-can-i-set-environment-variable-for-just-one-command-in-fish-shell)
for maximum fish compat could be the following:

```
begin
  set -lx TERM "$ssh_term"
  command ssh $ssh_opts $argv
end
```

According to `man set`, `-l` means local to the block and `-x` means
export.

I'm in favour of keeping `command` as it makes the integration more
predicable.

The reason I went with the current fix:
- It's easier to understand without knowing fish shell.
- [kat found that fish 3.1 should be widely
available](https://github.com/ghostty-org/ghostty/discussions/8021#discussioncomment-13877129).
2025-08-04 07:27:14 -04:00
Robbie Vanbrabant
42e4a95b64 fix fish shell syntax for ssh-env shell integration
As discussed here https://github.com/ghostty-org/ghostty/discussions/8021

This fixes invalid fish shell syntax.

As an example, run ghostty like so: `XDG_CONFIG_HOME=/tmp ghostty --shell-integration-features=ssh-env --command="/usr/bin/env fish"`. Setting XDG_CONFIG_HOME to /tmp is just to start from the default config.

Before:

```
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish
robbiev@neo ~/s/ghostty (fish-shell-ssh)> ssh git@github.com
env: ‘command’: No such file or directory
robbiev@neo ~/s/ghostty (fish-shell-ssh) [127]>
```

After:

```
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish
robbiev@neo ~/s/ghostty (fish-shell-ssh)> ssh git@github.com
PTY allocation request failed on channel 0
Hi robbiev! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.
robbiev@neo ~/s/ghostty (fish-shell-ssh) [1]>
```

My understanding of the fix follows.

The script is using `command` to make sure it calls the actual ssh binary and not some intermediate shell function with the same name (`man command` explains).

`env` can be useful for fish compat < 3.1, where [the KEY=value syntax was introduced](https://fishshell.com/docs/current/faq.html#how-do-i-set-or-clear-an-environment-variable). However because `command` is a builtin it doesn't work in this case.

So a simple solution is this, requiring fish >= 3.1

```
TERM="$ssh_term" command ssh $ssh_opts $argv
```

An [alternative](https://serverfault.com/questions/164305/how-can-i-set-environment-variable-for-just-one-command-in-fish-shell) for maximum fish compat could be the following:

```
begin
  set -lx TERM "$ssh_term"
  command ssh $ssh_opts $argv
end
```

According to `man set`, `-l` means local to the block and `-x` means export.

I'm in favour of keeping `command` as it makes the integration more predicable.

The reason I went with the current fix:
- It's easier to understand without knowing fish shell.
- [kat found that fish 3.1 should be widely available](https://github.com/ghostty-org/ghostty/discussions/8021#discussioncomment-13877129).
2025-08-04 11:28:39 +01:00
Jeffrey C. Ollie
83063e5527 gtk-ng: prevent split button from becoming focused 2025-08-03 13:38:49 -05:00
trag1c
f0272e5fec Added and updated translations for id_ID (#8126) 2025-08-03 17:36:43 +02:00
Mitchell Hashimoto
4efef78216 bash: upgrade to bash-preexec 0.6.0 (#8135)
https://github.com/rcaloras/bash-preexec/releases/tag/0.6.0

This is a small update for us because we've been using a patched version
of this script in Ghostty for some time, and the 0.6.0 release includes
most of the local changes we made as part of maintaining and improving
our bash shell integration.

- https://github.com/rcaloras/bash-preexec/pull/167
- https://github.com/rcaloras/bash-preexec/pull/170

We continue to maintain one local HISTCONTROL-related modification
(#2478). There are a few upstream conversations related to HISTCONTROL
that might eliminate the need for this local patch, so we may revisit
that in the future.
2025-08-03 06:44:19 -07:00
Jon Parise
f4e434fffd bash: upgrade to bash-preexec 0.6.0
https://github.com/rcaloras/bash-preexec/releases/tag/0.6.0

This is a small update for us because we've been using a patched version
of this script in Ghostty for some time, and the 0.6.0 release includes
most of the local changes we made as part of maintaining and improving
our bash shell integration.

- https://github.com/rcaloras/bash-preexec/pull/167
- https://github.com/rcaloras/bash-preexec/pull/170

We continue to maintain one local HISTCONTROL-related modification
(#2478). There are a few upstream conversations related to HISTCONTROL
that might eliminate the need for this local patch, so we may revisit
that in the future.
2025-08-03 09:15:35 -04:00
trag1c
6b57a23273 i18n: Updated translation for ko_KR (#8058) 2025-08-03 14:04:44 +02:00
Jinhyeok Lee
dbb1096c24 i18n: Update Korean translation metadata 2025-08-03 20:46:28 +09:00
mikailmm
b0ba0a1c8c fixed revision date
Co-authored-by: Kat <65649991+00-kat@users.noreply.github.com>
2025-08-03 12:21:37 +07:00
Mitchell Hashimoto
afdaab9cc6 apprt/gtk-ng: runtime CSS and custom CSS (#8133)
A simple port, nothing creative here.

Found one definite leak in GTK, added a suppression. No leaks in Ghostty
code.
2025-08-02 20:32:59 -07:00
Mitchell Hashimoto
8e8dc76362 Update iTerm2 colorschemes (#8132)
Upstream revision:
b2742b8baf
2025-08-02 20:30:22 -07:00
Mitchell Hashimoto
053e3d307b apprt/gtk-ng: runtime CSS and custom CSS 2025-08-02 20:28:22 -07:00
mitchellh
7a7790a212 deps: Update iTerm2 color schemes 2025-08-03 00:15:54 +00:00
Mitchell Hashimoto
78f474b143 apprt/gtk-ng: toggle_window_decorations (#8128) 2025-08-02 13:38:01 -07:00
Mitchell Hashimoto
5078fc5243 apprt/gtk-ng: toggle_window_decorations 2025-08-02 13:34:14 -07:00
Mitchell Hashimoto
7836cc8f31 apprt/gtk-ng: winproto behaviors (quick terminal, csd/ssd, blur, etc.) (#8123)
This ports over the winproto behaviors to gtk-ng. The core winproto
logic is unchanged except for trivial typing changes. The interaction
with winproto is a bit different in ng due to the class separation of
logic between surfaces and windows, but functionally the same.

Ran against Valgrind and all looks good.
2025-08-02 12:57:01 -07:00
Mitchell Hashimoto
91254bb6cc apprt/gtk-ng: address feedback 2025-08-02 12:53:27 -07:00
mikailmm
bebbeed81d added name and email in contribution list 2025-08-03 00:31:13 +07:00
mikailmm
a41cb2c827 Added last-translator name and email 2025-08-03 00:29:45 +07:00
Mitchell Hashimoto
e1e525ba3d apprt/gtk-ng: winproto callbacks for subprocess env 2025-08-01 21:16:08 -07:00
Mitchell Hashimoto
523799a45f apprt/gtk-ng: winproto resizeEvent 2025-08-01 21:05:42 -07:00
Mitchell Hashimoto
7aa84cd372 apprt/gtk-ng: quick terminal 2025-08-01 20:51:43 -07:00
Mitchell Hashimoto
084a20c865 apprt/gtk-ng: hook up all the syncAppearance calls for winproto 2025-08-01 14:58:25 -07:00
Mitchell Hashimoto
c7eee9ee7a apprt/gtk-ng: initialize window protocol 2025-08-01 14:40:19 -07:00
Mitchell Hashimoto
469001b7f6 apprt/gtk-ng: size_limit apprt action (#8116)
This ports the same behavior from GTK, mostly. This also fixes a bug
where the limits would be enforced on reload. Instead, we should only
enforce them on the first surface ever.
2025-08-01 08:06:40 -07:00
Mitchell Hashimoto
780d4af8bc apprt/gtk-ng: size_limit apprt action
This ports the same behavior from GTK, mostly. This also fixes a bug
where the limits would be enforced on reload. Instead, we should only
enforce them on the first surface ever.
2025-08-01 07:59:19 -07:00
mikailmm
b99831ce36 Update id_ID.UTF-8.po
added and changed the translation following the terminology used by Gnome (and Apple) from help.gnome.org and support.apple.com
2025-08-01 10:25:25 +07:00
Mitchell Hashimoto
1901cbf334 apprt/gtk-ng: initial size apprt action (window-width/height) (#8115)
Simple port. I might add size limits if I get to it, but finished this
and it works so opened it up.
2025-07-31 13:58:34 -07:00
Mitchell Hashimoto
0b9130aba9 apprt/gtk-ng: initial size apprt action (window-width/height) 2025-07-31 13:28:30 -07:00
Leah Amelia Chen
cf9943a3dd gtk(wayland): bind globals correctly (#8110) 2025-07-31 18:28:05 +02:00
Leah Amelia Chen
c2165fc097 gtk(wayland): bind globals correctly
Fixes #7988
2025-07-31 15:51:49 +08:00
Mitchell Hashimoto
d4c825186e apprt/gtk-ng: desktop notifications, open config, open url, present terminal (#8105)
Implements a number of minor apprt actions. More or less directly
ported. Some notes added for future improvements given the new
architecture.
2025-07-30 09:38:48 -07:00
Mitchell Hashimoto
6c952d4168 apprt/gtk-ng: desktop notification 2025-07-30 09:31:54 -07:00
Mitchell Hashimoto
e7ea084cc3 apprt/gtk-ng: present surface 2025-07-30 09:20:15 -07:00
Mitchell Hashimoto
60b859dbf2 apprt/gtk-ng: open config, open url 2025-07-30 09:04:01 -07:00
Mitchell Hashimoto
e7befe2ed1 apprt/gtk-ng: surface has correct initial size (#8104)
Ensure the surface has a correct initial size when created. This avoids
a rapid resize event and also the pty reports the correct size for
startup scripts.

This is a departure from macOS and legacy GTK. This has been an issue in
Ghostty for awhile so this is the proper path forward.

This works by deferring Surface initialization until the first resize
event. This MIGHT result in a frame or two not rendering but I haven't
noticed anything visually and having the correct size is far more
important.
2025-07-30 08:54:51 -07:00
Mitchell Hashimoto
7b1092f991 apprt/gtk-ng: surface has correct initial size
Ensure the surface has a correct initial size when created. This avoids
a rapid resize event and also the pty reports the correct size for
startup scripts.

This is a departure from macOS and legacy GTK. This has been an issue in
Ghostty for awhile so this is the proper path forward.

This works by deferring Surface initialization until the first resize
event. This MIGHT result in a frame or two not rendering but I haven't
noticed anything visually and having the correct size is far more
important.
2025-07-30 08:48:27 -07:00
Mitchell Hashimoto
1e721ae567 apprt/gtk-ng: tabs are back! (#8098)
This brings back all tabbing behaviors.

I ran through create/close tabs and windows with Valgrind and everything
ran clean.

TODO:

- [x] goto tab keybinding
- [x] move tab
- [x] toggle tab overview (binding only, UI works!)
- [x] create window action to pull tab out into a window
2025-07-30 07:13:38 -07:00
Anthony
db2984de6e cli: update var name 2025-07-30 14:29:38 +10:00
Mitchell Hashimoto
fde50e0f1c apprt/gtk-ng: create-window action 2025-07-29 15:07:04 -07:00
Mitchell Hashimoto
0cc8b6d10f apprt/gtk-ng: remove all shortcuts on tab view 2025-07-29 14:57:50 -07:00
Mitchell Hashimoto
2847aeb181 apprt/gtk-ng: toggle tab overview 2025-07-29 14:56:16 -07:00
Mitchell Hashimoto
a5188142ba apprt/gtk-ng: move tab 2025-07-29 14:52:33 -07:00
Mitchell Hashimoto
2d1232878d apprt/gtk-ng: goto_tab 2025-07-29 14:40:45 -07:00
Mitchell Hashimoto
c78d32074e Add Gnome Nightly Icon Set (#8100)
This adds a nightly-variant for the icons. These aren't hooked up to our
build system yet.

<img width="1024" height="1024" alt="Ghostty-Gnome-Nightly-512"
src="https://github.com/user-attachments/assets/66da56a4-110a-4e60-8d6e-93e16bb27b51"
/>
2025-07-29 12:15:54 -07:00
Mitchell Hashimoto
a705b42899 Add Gnome Nightly Icon Set
This adds a nightly-variant for the icons. These aren't hooked up to our
build system yet.
2025-07-29 12:10:42 -07:00
Mitchell Hashimoto
4fb790ca4c apprt/gtk-ng: helper for getAncestor 2025-07-29 10:58:31 -07:00
Mitchell Hashimoto
179fa8e5aa remove bad file 2025-07-29 10:43:20 -07:00
Mitchell Hashimoto
8b14ab1221 apprt/gtk-ng: workaround for tab overview selection 2025-07-29 10:39:45 -07:00
Mitchell Hashimoto
16bb579bab update supps 2025-07-29 10:32:03 -07:00
Mitchell Hashimoto
0da6b2049d apprt/gtk-ng: tab overview new tab 2025-07-29 10:29:28 -07:00
Mitchell Hashimoto
ccc8dac0a5 apprt/gtk-ng: new tab button 2025-07-29 10:24:25 -07:00
Mitchell Hashimoto
b475cd28d5 apprt/gtk-ng: new tab, slightly broken 2025-07-29 10:17:26 -07:00
Mitchell Hashimoto
0682811107 apprt/gtk-ng: window close confirmation 2025-07-29 09:48:17 -07:00
Mitchell Hashimoto
70010ec50a typos 2025-07-29 09:38:31 -07:00
Mitchell Hashimoto
e4fb46f230 apprt/gtk-ng: close window if no tabs left 2025-07-29 09:38:09 -07:00
Mitchell Hashimoto
3bb6cdff4e apprt/gtk-ng: window getActiveSurface 2025-07-29 09:33:38 -07:00
Mitchell Hashimoto
3f440821d9 fix up suppressions 2025-07-29 09:29:50 -07:00
Mitchell Hashimoto
c0e7b92e91 apprt/gtk-ng: close tab confirmation 2025-07-29 09:27:13 -07:00
Mitchell Hashimoto
431a6328dc apprt/gtk-ng: handle surface close request 2025-07-28 21:38:00 -07:00
Mitchell Hashimoto
ed25a57d08 apprt/gtk-ng: hook up all existing surface signals 2025-07-28 21:22:23 -07:00
Mitchell Hashimoto
5279badd5b apprt/gtk-ng: bind a bunch on page-attach/detach 2025-07-28 21:08:47 -07:00
Mitchell Hashimoto
fa45f971f4 apprt/gtk-ng: title bindings 2025-07-28 12:38:40 -07:00
Mitchell Hashimoto
775f3dfca3 apprt/gtk-ng: basic tab creation 2025-07-28 10:52:33 -07:00
Mitchell Hashimoto
e768b54d89 apprt/gtk-ng: new tab button in header 2025-07-28 10:21:47 -07:00
Mitchell Hashimoto
bc6cbdc41a apprt/gtk-ng: toolbar style config 2025-07-28 10:21:47 -07:00
Mitchell Hashimoto
d7e42e6614 apprt/gtk-ng: tab bar top/bottom 2025-07-28 10:21:47 -07:00
Mitchell Hashimoto
e7cab27c38 apprt/gtk-ng: tab bar properties 2025-07-28 10:21:47 -07:00
Mitchell Hashimoto
288461fbee apprt/gtk-ng: setup tab views in blueprint 2025-07-28 10:21:47 -07:00
Mitchell Hashimoto
92c1f4b0b9 macOS: update Float on Top menu icon to square.filled.on.square (#8087)
Address a minor UI confusion introduced by #7594.

Ghostty's "Float on Top" action icon uses
`square.3.layers.3d.top.filled`, which is the same as macOS's "Bring All
to Front" action. This may cause confusion.

Before:
<img width="333" height="156" alt="image"
src="https://github.com/user-attachments/assets/5148909c-f090-4b2f-8206-c45cb30cf30e"
/>

After:
<img width="336" height="148" alt="image"
src="https://github.com/user-attachments/assets/3c3a820f-ece3-4778-af47-767758c23266"
/>
2025-07-28 10:01:14 -07:00
Mitchell Hashimoto
3278507ae8 Fix typo in VM Acceptance Criteria (#8092)
This PR fixes a small typo in the "VM Acceptance Criteria" section —
replaces "The" with "They".
2025-07-28 10:01:03 -07:00
Ahmed Harabi
87bb949a93 Fix typo in VM Acceptance Criteria ('The' → 'They') 2025-07-28 15:57:48 +00:00
Mitchell Hashimoto
a5a09f5ba4 apprt/gtk-ng: port SIGUSR2 to reload config (#8091)
Nothing controversial here.
2025-07-28 08:33:22 -07:00
Mitchell Hashimoto
c149ba1907 apprt/gtk-ng: port SIGUSR2 to reload config 2025-07-28 08:21:28 -07:00
Mitchell Hashimoto
d474c81b90 gtk-ng: fix up background of resize and url overlays (#8089)
PR #8088 had the unexpected side-effect of making the resize and url
overlays transparent as well. This PR fixes that.
2025-07-27 21:33:59 -07:00
Jeffrey C. Ollie
96573917a0 gtk-ng: fix up background of resize and url overlays
PR #8088 had the unexpected side-effect of making the resize and url
overlays transparent as well. This PR fixes that.
2025-07-27 23:28:28 -05:00
Mitchell Hashimoto
4c01d776c5 valgrind: make some GSK renderer supressions less strict 2025-07-27 21:08:15 -07:00
Mitchell Hashimoto
466aab543f gtk-ng: add/remove 'background' css class from window depending on opacity (#8088) 2025-07-27 21:04:11 -07:00
Jeffrey C. Ollie
92c004cb25 gtk-ng: add/remove 'background' css class from window depending on opacity 2025-07-27 22:05:16 -05:00
Mitchell Hashimoto
520ba27bb7 build(deps): bump cachix/install-nix-action from 31.5.1 to 31.5.2 (#8086)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.5.1 to 31.5.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.5.2</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.30.1 -&gt; 2.30.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/246">cachix/install-nix-action#246</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31...v31.5.2">https://github.com/cachix/install-nix-action/compare/v31...v31.5.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="fc6e360bed"><code>fc6e360</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/246">#246</a>
from cachix/create-pull-request/patch</li>
<li><a
href="9d5112343e"><code>9d51123</code></a>
nix: 2.30.1 -&gt; 2.30.2</li>
<li>See full diff in <a
href="c134e4c9e3...fc6e360bed">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.5.1&new-version=31.5.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-07-27 19:58:31 -07:00
Aaron Ruan
1f710768e9 Update Float on Top menu icon to square.filled.on.square 2025-07-28 09:26:54 +08:00
dependabot[bot]
b5a34f5f3c build(deps): bump cachix/install-nix-action from 31.5.1 to 31.5.2
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.5.1 to 31.5.2.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](c134e4c9e3...fc6e360bed)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-28 01:05:10 +00:00
Mitchell Hashimoto
75d5a519c8 apprt/gtk-ng: configuration reloading, toasts (#8084)
This brings in configuration reloading and toasts to gtk-ng. 

Config reloading is fairly different in ng than legacy because we rely
on our GObject `Config` class and ref counting more heavily. We rely on
various property bindings and notify signals to propagate configuration
changes out to all subscribers. Previously we manually had to chain this
together.

Toasts are straightforward, with the main difference being that the
window owns its own toasts (surfaces can't trigger them) and triggers
them via signal emission.
2025-07-27 15:20:10 -07:00
Mitchell Hashimoto
bf61f29f57 apprt/gtk-ng: create the privateObjFieldAccessor helper to unref 2025-07-27 15:11:07 -07:00
Mitchell Hashimoto
c4de001023 apprt/gtk-ng: avoid reading corrupt memory in event loop 2025-07-27 14:28:21 -07:00
Mitchell Hashimoto
b011706aad suppressions 2025-07-27 14:12:26 -07:00
Mitchell Hashimoto
53c7b8922f apprt/gtk-ng: reload config 2025-07-27 13:57:28 -07:00
Mitchell Hashimoto
ccde429bde apprt/gtk-ng: toasts 2025-07-27 13:27:03 -07:00
Anthony
487b1d72ab cli: add filtering hotkey to list_themes 2025-07-27 17:45:12 +10:00
Mitchell Hashimoto
18831374ca apprt/gtk-ng: fix scrolling on surface (#8080)
We forgot to specify the scroll controller's `flags` property.
2025-07-26 12:17:09 -07:00
Mitchell Hashimoto
b5c1f52ddb apprt/gtk-ng: fix scrolling on surface
We forgot to specify the scroll controller's `flags` property.
2025-07-26 12:13:51 -07:00
Mitchell Hashimoto
fd1db0c8e6 apprt/gtk-ng: new window menu action
Not sure why I skipped this one, its super easy.
2025-07-26 07:29:15 -07:00
Mitchell Hashimoto
c24aa0e9be update valgrind suppressions for a Linux wayland machine 2025-07-26 07:23:34 -07:00
Mitchell Hashimoto
b389171476 Add per-font size adjustment, don't adjust nf symbol font or emoji font; use non-Mono symbols nerd font (#7953)
This adds functionality for choosing different normalization metrics for
each fallback font. It's not exposed as a config option, but could be in
the future, which would probably go a long way towards addressing
concerns like #7929.

The currently available reference metrics are, in priority order:
`ic_width, ex_height, cap_height, line_height, em_size`. The default
value is `ic_width`.

By priority order, I mean that if the chosen metric is not defined in
the fallback font, we move to the next metric in the list---we don't
normalize by an estimated metric from the fallback font (however, we're
happy to use an estimated metric from the primary font, that's how
`ic_width` normalization between CJK and Latin fonts work). This extends
the pattern that was used between `ic_width` and `ex_height` in the
existing hardcoded rule. `line_height` is always defined, so the buck
stops there.

What motivated me to implement this was the fact that, with the existing
hardcoded rule, the embedded symbols-only Nerd Font was always scaled up
by a factor of 1.2, which turned out to be an important reason why it's
been difficult to make icon scaling work to everyone's satisfaction.
Accordingly, the symbols-only font is the first to take advantage of the
new functionality. If this PR is merged, #7917 is no longer needed. (To
limit the scope of this PR, it only includes the minimal changes to let
icon scaling take advantage of this functionality. I may submit a
follow-up PR with some further icon scaling improvement enabled by
this.)
2025-07-26 07:08:44 -07:00
Mitchell Hashimoto
fcbc58401f Upgrade hustcer/milestone-action to v2.9 (#8074)
Upgrade
[hustcer/milestone-action](https://github.com/hustcer/milestone-action)
to v2.9, [Release
Detail](https://github.com/hustcer/milestone-action/releases/tag/v2.9)

Fix the deprecated warning here:
https://github.com/ghostty-org/ghostty/actions/runs/16531137360/job/46756561930#step:3:37
2025-07-26 07:01:12 -07:00
Mitchell Hashimoto
bdf14cf29d gtk-ng: add ipc infrastructure and connect +new-window ipcs (#8069) 2025-07-26 07:00:59 -07:00
hustcer
259266223c Upgrade hustcer/milestone-action to v2.9 2025-07-26 11:57:13 +08:00
Jeffrey C. Ollie
ed584e769f gtk-ng: add ipc infrastructure and connect +new-window ipcs 2025-07-25 22:48:39 -05:00
Mitchell Hashimoto
858e705973 apprt/gtk-ng: window headerbar, maximize, fullscreen (#8071)
This ports over a basic headerbar, maximize, and fullscreen. The
headerbar only has the main menu button for now since we have no tabbing
or splits. The main menu has the full main menu that mainline GTK has
but most of it is disabled since we don't implement the actions yet.

I didn't use anything from your branch @tristan957 so I didn't add
coauthor but I want to note that @tristan957 worked on this as well and
I suspect there's overlap.
2025-07-25 20:45:41 -07:00
Mitchell Hashimoto
a8d0a84530 apprt/gtk-ng: hook up window close confirmation 2025-07-25 15:12:55 -07:00
Mitchell Hashimoto
a25a0011ea apprt/gtk-ng: more actions 2025-07-25 14:53:18 -07:00
Mitchell Hashimoto
7d33d39a45 blp formatting 2025-07-25 13:56:41 -07:00
Mitchell Hashimoto
7f2f603fbd apprt/gtk-ng: handle headerbar visibility by config 2025-07-25 13:52:12 -07:00
Mitchell Hashimoto
20b6d8ad79 gtk-ng: tell systemd when Ghostty is ready (#8070) 2025-07-25 13:36:45 -07:00
Mitchell Hashimoto
5fd7e0814d typos 2025-07-25 13:36:05 -07:00
Mitchell Hashimoto
7f3dda7ea4 apprt/gtk-ng: setup headervar-visible binding 2025-07-25 13:35:43 -07:00
Mitchell Hashimoto
6cf8007cf7 apprt/gtk-ng: toggle fullscreen and maximize 2025-07-25 13:17:13 -07:00
Jeffrey C. Ollie
95df073455 gtk-ng: tell systemd when Ghostty is ready 2025-07-25 15:16:50 -05:00
Mitchell Hashimoto
5b37e86391 apprt/gtk-ng: close surface, close window 2025-07-25 12:59:47 -07:00
Mitchell Hashimoto
f27fd0f550 apprt/gtk-ng: main menu button shouldn't focus 2025-07-25 12:47:26 -07:00
Mitchell Hashimoto
297e9cb8ab new suppressions to deal solely with showing the about window 2025-07-25 12:19:34 -07:00
Mitchell Hashimoto
02e6ef7e9b apprt/gtk-ng: setup action maps in app and window 2025-07-25 12:10:30 -07:00
Mitchell Hashimoto
e865535f6e apprt/gtk-ng: simple headerbar 2025-07-25 12:10:11 -07:00
Mitchell Hashimoto
b8dd767fe4 apprt/gtk: fix double-free if quit action is used (#8068)
This fixes a double-free that Valgrind found when the quit action was
used (the keybinding to quit or the menu item). This fixes it in both
the gtk and gtk-ng apprts.

The issue stems from the fact that our quit action worked by traversing
the toplevels and destroying all windows. When all windows are
destroyed, GTK exits the main loop.

When fcitx is used as the input method editor (IME), it appears to hold
its own `gtk.Window` widget as a property (probably for the IME popup).
Unfortunately this does not react well to being destroyed externally and
triggers a double-free when the IME widget also tries to dispose itself.

I think this is probably a bug somewhere in the GTK IME widget because
it should be resilient to this kind of destruction. But, we can't
tolerate a double free in the mean time.

We can still quit by destroying only OUR windows (which cascades to
destroy everything else).
2025-07-25 12:01:54 -07:00
Mitchell Hashimoto
a477921b80 apprt/gtk: fix double-free if quit action is used
This fixes a double-free that Valgrind found when the quit action was
used (the keybinding to quit or the menu item). 

The issue stems from the fact that our quit action worked by traversing the 
toplevels and destroying all windows. When all windows are destroyed,
GTK exits the main loop.

When fcitx is used as the input method editor (IME), it appears to hold
its own `gtk.Window` widget as a property (probably for the IME popup).
Unfortunately this does not react well to being destroyed externally and
triggers a double-free when the IME widget also tries to dispose itself.

I think this is probably a bug somewhere in the GTK IME widget because
it should be resilient to this kind of destruction. But, we can't
tolerate a double free in the mean time.

We can still quit by destroying only OUR windows (which cascades to
destroy everything else).
2025-07-25 11:53:22 -07:00
Qwerasd
92fa2228e9 font: use non-mono symbols nerd font for embedded symbols
I changed my mind, this is a pretty small change and relevant to the
intent of the PR. This brings the appearance of the embedded symbols
much closer to patched fonts.

With this, the sizes of most symbols are nearly identical to a patched
font, the only big difference is positioning (and TBH I think we do a
better job positioning than the patcher does, since we have knowledge
about the cell size).
2025-07-25 12:41:00 -06:00
Jeffrey C. Ollie
abfab82ef7 gtk-ng: add debug warning banner (#8057) 2025-07-25 13:18:58 -05:00
Qwerasd
6af6357949 font: clean up Collection api somewhat
Move size adjustment logic out of `Entry`, I understand the impulse to
put it there but it results in passing a lot of stuff around which isn't
great.

Rework `add(...)` in to `add(...)` and `addDeferred(...)`, faces are
passed directly now instead of passing an entry, and an options struct
is used instead of positional arguments for things like style, fallback,
and size adjustment.

Change size adjustment test back to a half pixel tolerance instead of 5%
because the previous commit (allowing fractional pixel sizes) fixed the
root cause of large differences.
2025-07-25 11:50:59 -06:00
Jeffrey C. Ollie
f390941fd6 gtk-ng: move debug property to window 2025-07-25 12:46:56 -05:00
Jeffrey C. Ollie
33135f19dc gtk-ng: add debug warning banner 2025-07-25 12:46:55 -05:00
Qwerasd
9405522dd5 font: allow fractional pixel sizes 2025-07-25 11:36:03 -06:00
Mitchell Hashimoto
3cdd6f4f5e apprt/gtk-ng: surface inheritance, new window (#8067)
This makes the `new_window` action properly inherit properties from the
parent surface that initiated the action. Today, that is only the pwd
and font size.
2025-07-25 10:29:45 -07:00
Mitchell Hashimoto
830d49c185 apprt/gtk-ng: surface inheritance, new window
This makes the `new_window` action properly inherit properties from the
parent surface that initiated the action. Today, that is only the pwd
and font size.
2025-07-25 10:17:08 -07:00
Mitchell Hashimoto
787960e56d apprt/gtk-ng: hook up bell ringing (#8065)
For now, this just emits a signal that an embedding widget will react to
to do something like flashing the window.

I think we should implement the audio bell in the actual surface view
but I don't currently have audio drivers hooked up in my Linux VM and
I'm away from my desktop PC. :)

cc @jcollie if you're interested, pretty tightly scoped.
2025-07-25 09:29:16 -07:00
Mitchell Hashimoto
b36b7031a1 apprt/gtk-ng: hook up bell ringing
For now, this just emits a signal that an embedding widget will react to
to do something like flashing the window. 

I think we should implement the audio bell in the actual surface view
but I don't currently have audio drivers hooked up in my Linux VM and
I'm away from my desktop PC. :)
2025-07-25 09:01:45 -07:00
Mitchell Hashimoto
6d6b911fad macos: add more Tahoe menu item icons from SF Symbols (#8050)
This is a follow up to https://github.com/ghostty-org/ghostty/pull/7594
<img width="487" height="318" alt="Screenshot 2025-07-24 at 23 10 20"
src="https://github.com/user-attachments/assets/83491b18-ef64-4a8f-b63d-a0001352cc31"
/>
<img width="544" height="295" alt="Screenshot 2025-07-24 at 23 11 01"
src="https://github.com/user-attachments/assets/10922879-ac1b-409d-8a3b-c298a1411813"
/>
2025-07-25 07:24:11 -07:00
Weizhao Ouyang
b7f6da7857 macos: add more Tahoe menu item icons from SF Symbols
Signed-off-by: Weizhao Ouyang <o451686892@gmail.com>
2025-07-25 22:14:13 +08:00
Jinhyeok Lee
0a8e71f862 i18n: Updated translation for ko_KR 2025-07-25 12:56:50 +09:00
Qwerasd
c0ee4a252a font: revert switch to non-mono symbols nerd font
This change might be good, but it is incomplete and not relevant to the
PR that it's a part of. I'll explore making this change separately after
this, since it might be a good idea.

(It's incomplete since the attribute data was not re-generated based on
the non-mono file.)
2025-07-24 17:52:41 -06:00
Qwerasd
2054a06533 cleanup
A variety of naming, commenting, and formatting improvements + a few
explicit error sets. This commit has no functional changes, though it
does remove a couple functions that didn't really need to exist.
2025-07-24 17:48:57 -06:00
trag1c
03ea024bc1 i18n: Updated translation for nl_NL (#8040) 2025-07-24 21:29:40 +02:00
Mitchell Hashimoto
8016e0be6d Fix tab titles not being preserved with window-save-state (#8037)
Fixes #7938



https://github.com/user-attachments/assets/766a5d7a-f660-428f-b82b-3eafea83eff3
2025-07-23 16:48:35 -07:00
Mitchell Hashimoto
70f6e8b03f apprt/gtk-ng: surface progress bar (#8045)
Straightforward port of existing functionality. No memory leaks
detected.
2025-07-23 16:39:19 -07:00
Mitchell Hashimoto
00cce91dc4 apprt/gtk-ng: surface progress bar 2025-07-23 16:29:56 -07:00
Mitchell Hashimoto
eb3f3fff83 apprt/gtk-ng: keep child_exited property up to date 2025-07-23 16:03:27 -07:00
Mitchell Hashimoto
9a3239ba9f apprt/gtk-ng: child exited overlay (#8044)
This ports the child exited overlay.

We're able to use Zig comptime and Blueprint templates to use the same
Surface blueprint for this even if libadwaita is too old to support
banners (< 1.3) by inheriting from `gtk.Widget` instead and not
instantiating the blueprint. Its a bit noisy to maintain the `noop`
version but we should be able to test that compilation in CI (we do via
Debian 12).
2025-07-23 16:01:35 -07:00
Mitchell Hashimoto
cd664078ad apprt/gtk-ng: child exited overlay 2025-07-23 15:47:44 -07:00
Jeffrey C. Ollie
8571bd67f9 devshell: add deps that allow GTK to load SVG resources (#8041)
GTK dynamically loads librsvg when it needs to convert a SVG-only icon
(or any other SVG-only resource) for display. This PR adds the libraries
that GTK needs so that running programs from within the developer shell
can display those SVG resources.
2025-07-23 16:09:20 -05:00
Jeffrey C. Ollie
3dc45fcd55 devshell: add deps that allow GTK to load SVG resources
GTK dynamically loads librsvg when it needs to convert a SVG-only icon
(or any other SVG-only resource) for display. This PR adds the libraries
that GTK needs so that running programs from within the developer shell
can display those SVG resources.
2025-07-23 15:48:00 -05:00
Merijntje Tak
e8ab00aa4b Added translation for nl_NL 2025-07-23 22:37:03 +02:00
Mitchell Hashimoto
f7424c8a76 apprt/gtk-ng: surface drag and drop (#8039) 2025-07-23 12:48:43 -07:00
Mitchell Hashimoto
550d29d930 apprt/gtk-ng: surface drag and drop 2025-07-23 12:35:31 -07:00
Mitchell Hashimoto
9ea87ec096 New icon for Linux GTK app that aligns with the Gnome HIG (#8038)
This adds a new icon for the GTK-based application that adheres (mostly)
to the Gnome Human Interface Guidelines (HIG). The icon is designed to
fit in better with other Gnome applications.

While there isn't a single standard "native" style amongst Linux
applications, I believe this better fits the general Linux desktop
ecosystem over our macOS icon.

The icon itself is undeniably Ghostty. The core design language is the
same and I don't think ayone will mistake it for anything else. I wanted
to keep the brand the same, but making it fit in better aligns with
Ghostty's goal of being "platform native".

As of this PR, you can't use the macOS icon on Linux without modifying
the source. We may provide a compile-time option to swap icons in the
future (unfortunately Linux desktop applications require hardcoding an
icon path in the desktop files, so making it runtime selectable is...
messy!)

<img width="2048" height="2048" alt="2048"
src="https://github.com/user-attachments/assets/0b15e6db-bb6d-424c-8a83-ca809759b0c4"
/>
2025-07-23 10:06:19 -07:00
Mitchell Hashimoto
b50c1c4fa0 New icon for Linux GTK app that aligns with the Gnome HIG
This adds a new icon for the GTK-based application that adheres (mostly)
to the Gnome Human Interface Guidelines (HIG). The icon is designed to
fit in better with other Gnome applications. 

While there isn't a single standard "native" style amongst Linux
applications, I believe this better fits the general Linux desktop
ecosystem over our macOS icon.

The icon itself is undeniably Ghostty. The core design language is the
same and I don't think ayone will mistake it for anything else. I wanted
to keep the brand the same, but making it fit in better aligns with
Ghostty's goal of being "platform native".
2025-07-23 10:00:55 -07:00
Bryan Lee
852eb2e0d5 Fix tab titles not being preserved with window-save-state
Add serialization for tab titles in SurfaceView to persist user-set titles across app restarts. Bump TerminalRestorableState version to 4 to handle the new format.
2025-07-23 23:21:44 +08:00
Mitchell Hashimoto
df57f17be8 apprt/gtk-ng: bind template callbacks so we can connect signals in blp (#8035)
This creates a helper so that we can call
[`gtk_widget_class_bind_template_callback_full`](https://docs.gtk.org/gtk4/class_method.Widget.bind_template_callback_full.html)
and register signal handlers directly in our Blueprint file. This gets
rid of a LOT of boilerplate!

A draft, since there are TODOs:

- [x] Add comptime verification of the `func` param
- [x] Convert more blueprint files
2025-07-23 07:30:25 -07:00
Mitchell Hashimoto
010e9199ca apprt/gtk-ng: bind template callbacks so we can connect signals in blp 2025-07-23 07:24:00 -07:00
Mitchell Hashimoto
2e68f0a4d4 update zig-gobject pick up fix for ianprime0509/zig-gobject#111 (#8036) 2025-07-23 07:01:48 -07:00
Jeffrey C. Ollie
80b72dd6cb update zig-gobject pick up fix for ianprime0509/zig-gobject#111 2025-07-22 23:45:19 -05:00
Daniel Wennberg
652bae7379 Update a straggling name and signature 2025-07-18 00:58:08 -07:00
Daniel Wennberg
a7c560c159 Calculate scaled size directly, eliminate redundant resizes 2025-07-18 00:58:08 -07:00
Daniel Wennberg
054b7325dc Add unwrapConst, avoid constCast 2025-07-17 17:27:45 -07:00
Daniel Wennberg
ce507f35df Use em size as nerd font reference metric 2025-07-17 17:04:47 -07:00
Daniel Wennberg
e7d28a85c8 Make size normalization reference customizable per face 2025-07-17 17:04:47 -07:00
Daniel Wennberg
6491ea41fb Move face metric fallback estimates to the FaceMetric struct 2025-07-17 15:45:47 -07:00
222 changed files with 19983 additions and 3834 deletions

View File

@@ -15,7 +15,7 @@ jobs:
name: Milestone Update
steps:
- name: Set Milestone for PR
uses: hustcer/milestone-action@09bdc6fda0f43a4df28cda5815cc47df74cfdba7 # v2.8
uses: hustcer/milestone-action@b57a7e52e9913b6b0cdefb10add762af0398659d # v2.9
if: github.event.pull_request.merged == true
with:
action: bind-pr # `bind-pr` is the default action
@@ -24,7 +24,7 @@ jobs:
# Bind milestone to closed issue that has a merged PR fix
- name: Set Milestone for Issue
uses: hustcer/milestone-action@09bdc6fda0f43a4df28cda5815cc47df74cfdba7 # v2.8
uses: hustcer/milestone-action@b57a7e52e9913b6b0cdefb10add762af0398659d # v2.9
if: github.event.issue.state == 'closed'
with:
action: bind-issue

View File

@@ -34,15 +34,15 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- name: Setup Nix
uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16

View File

@@ -8,7 +8,7 @@ jobs:
runs-on: namespace-profile-ghostty-sm
needs: [build-macos-debug]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Install sentry-cli
run: |
@@ -29,7 +29,7 @@ jobs:
runs-on: namespace-profile-ghostty-sm
needs: [build-macos]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Install sentry-cli
run: |
@@ -47,19 +47,19 @@ jobs:
sentry-cli dif upload --project ghostty --wait dsym.zip
build-macos:
runs-on: namespace-profile-ghostty-macos-sequoia
runs-on: namespace-profile-ghostty-macos-tahoe
timeout-minutes: 90
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Important so that build number generation works
fetch-depth: 0
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: DeterminateSystems/nix-installer-action@main
with:
nix_path: nixpkgs=channel:nixos-unstable
determinate: true
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
@@ -68,7 +68,7 @@ jobs:
# Setup Sparkle
- name: Setup Sparkle
env:
SPARKLE_VERSION: 2.6.4
SPARKLE_VERSION: 2.7.1
run: |
mkdir -p .action/sparkle
cd .action/sparkle
@@ -95,6 +95,7 @@ jobs:
run: |
cd macos
sudo xcode-select -s /Applications/Xcode_26.0.app
xcodebuild -version
xcodebuild -target Ghostty -configuration Release
# We inject the "build number" as simply the number of commits since HEAD.
@@ -201,19 +202,19 @@ jobs:
destination-dir: ./
build-macos-debug:
runs-on: namespace-profile-ghostty-macos-sequoia
runs-on: namespace-profile-ghostty-macos-tahoe
timeout-minutes: 90
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Important so that build number generation works
fetch-depth: 0
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: DeterminateSystems/nix-installer-action@main
with:
nix_path: nixpkgs=channel:nixos-unstable
determinate: true
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
@@ -222,7 +223,7 @@ jobs:
# Setup Sparkle
- name: Setup Sparkle
env:
SPARKLE_VERSION: 2.5.1
SPARKLE_VERSION: 2.7.1
run: |
mkdir -p .action/sparkle
cd .action/sparkle
@@ -249,6 +250,7 @@ jobs:
run: |
cd macos
sudo xcode-select -s /Applications/Xcode_26.0.app
xcodebuild -version
xcodebuild -target Ghostty -configuration Release
# We inject the "build number" as simply the number of commits since HEAD.

View File

@@ -56,7 +56,7 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Important so that build number generation works
fetch-depth: 0
@@ -80,16 +80,16 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -120,7 +120,7 @@ jobs:
build-macos:
needs: [setup]
runs-on: namespace-profile-ghostty-macos-sequoia
runs-on: namespace-profile-ghostty-macos-tahoe
timeout-minutes: 90
env:
GHOSTTY_VERSION: ${{ needs.setup.outputs.version }}
@@ -128,11 +128,11 @@ jobs:
GHOSTTY_COMMIT: ${{ needs.setup.outputs.commit }}
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: DeterminateSystems/nix-installer-action@main
with:
nix_path: nixpkgs=channel:nixos-unstable
determinate: true
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
@@ -141,9 +141,12 @@ jobs:
- name: XCode Select
run: sudo xcode-select -s /Applications/Xcode_16.4.app
- name: Xcode Version
run: xcodebuild -version
- name: Setup Sparkle
env:
SPARKLE_VERSION: 2.6.4
SPARKLE_VERSION: 2.7.1
run: |
mkdir -p .action/sparkle
cd .action/sparkle
@@ -279,7 +282,7 @@ jobs:
curl -sL https://sentry.io/get-cli/ | bash
- name: Download macOS Artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: macos
@@ -291,7 +294,7 @@ jobs:
appcast:
needs: [setup, build-macos]
runs-on: namespace-profile-ghostty-macos-sequoia
runs-on: namespace-profile-ghostty-macos-tahoe
env:
GHOSTTY_VERSION: ${{ needs.setup.outputs.version }}
GHOSTTY_BUILD: ${{ needs.setup.outputs.build }}
@@ -299,16 +302,16 @@ jobs:
GHOSTTY_COMMIT_LONG: ${{ needs.setup.outputs.commit_long }}
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Download macOS Artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: macos
- name: Setup Sparkle
env:
SPARKLE_VERSION: 2.6.4
SPARKLE_VERSION: 2.7.1
run: |
mkdir -p .action/sparkle
cd .action/sparkle
@@ -350,17 +353,17 @@ jobs:
GHOSTTY_VERSION: ${{ needs.setup.outputs.version }}
steps:
- name: Download macOS Artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: macos
- name: Download Sparkle Artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: sparkle
- name: Download Source Tarball Artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: source-tarball

View File

@@ -19,7 +19,7 @@ jobs:
runs-on: namespace-profile-ghostty-sm
needs: [build-macos]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Tip Tag
run: |
git config user.name "github-actions[bot]"
@@ -31,7 +31,7 @@ jobs:
runs-on: namespace-profile-ghostty-sm
needs: [build-macos-debug-slow]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Install sentry-cli
run: |
@@ -52,7 +52,7 @@ jobs:
runs-on: namespace-profile-ghostty-sm
needs: [build-macos-debug-fast]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Install sentry-cli
run: |
@@ -73,7 +73,7 @@ jobs:
runs-on: namespace-profile-ghostty-sm
needs: [build-macos]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Install sentry-cli
run: |
@@ -105,14 +105,14 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -154,19 +154,19 @@ jobs:
)
}}
runs-on: namespace-profile-ghostty-macos-sequoia
runs-on: namespace-profile-ghostty-macos-tahoe
timeout-minutes: 90
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Important so that build number generation works
fetch-depth: 0
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
# TODO(tahoe): https://github.com/NixOS/nix/issues/13342
- uses: DeterminateSystems/nix-installer-action@main
with:
nix_path: nixpkgs=channel:nixos-unstable
determinate: true
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
@@ -181,7 +181,7 @@ jobs:
# Setup Sparkle
- name: Setup Sparkle
env:
SPARKLE_VERSION: 2.6.4
SPARKLE_VERSION: 2.7.1
run: |
mkdir -p .action/sparkle
cd .action/sparkle
@@ -374,19 +374,19 @@ jobs:
)
}}
runs-on: namespace-profile-ghostty-macos-sequoia
runs-on: namespace-profile-ghostty-macos-tahoe
timeout-minutes: 90
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Important so that build number generation works
fetch-depth: 0
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
# TODO(tahoe): https://github.com/NixOS/nix/issues/13342
- uses: DeterminateSystems/nix-installer-action@main
with:
nix_path: nixpkgs=channel:nixos-unstable
determinate: true
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
@@ -401,7 +401,7 @@ jobs:
# Setup Sparkle
- name: Setup Sparkle
env:
SPARKLE_VERSION: 2.5.1
SPARKLE_VERSION: 2.7.1
run: |
mkdir -p .action/sparkle
cd .action/sparkle
@@ -554,19 +554,19 @@ jobs:
)
}}
runs-on: namespace-profile-ghostty-macos-sequoia
runs-on: namespace-profile-ghostty-macos-tahoe
timeout-minutes: 90
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
# Important so that build number generation works
fetch-depth: 0
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
# TODO(tahoe): https://github.com/NixOS/nix/issues/13342
- uses: DeterminateSystems/nix-installer-action@main
with:
nix_path: nixpkgs=channel:nixos-unstable
determinate: true
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
@@ -581,7 +581,7 @@ jobs:
# Setup Sparkle
- name: Setup Sparkle
env:
SPARKLE_VERSION: 2.5.1
SPARKLE_VERSION: 2.7.1
run: |
mkdir -p .action/sparkle
cd .action/sparkle

View File

@@ -13,16 +13,14 @@ jobs:
- build-bench
- build-dist
- build-flatpak
- build-freebsd
- build-linux
- build-linux-libghostty
- build-nix
- build-snap
- build-macos
- build-macos-tahoe
- build-macos-matrix
- build-windows
- flatpak-check-zig-cache
- flatpak
- test
- test-gtk
- test-gtk-ng
@@ -36,8 +34,10 @@ jobs:
- translations
- blueprint-compiler
- test-pkg-linux
- test-debian-12
- test-debian-13
- valgrind
- zig-fmt
- flatpak
steps:
- id: status
name: Determine status
@@ -67,17 +67,17 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -98,17 +98,17 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -134,17 +134,17 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -163,17 +163,17 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -196,17 +196,17 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -240,17 +240,17 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -272,16 +272,16 @@ jobs:
ghostty-source.tar.gz
build-macos:
runs-on: namespace-profile-ghostty-macos-sequoia
runs-on: namespace-profile-ghostty-macos-tahoe
needs: test
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
# TODO(tahoe): https://github.com/NixOS/nix/issues/13342
- uses: DeterminateSystems/nix-installer-action@main
with:
nix_path: nixpkgs=channel:nixos-unstable
determinate: true
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
@@ -314,12 +314,12 @@ jobs:
cd macos
xcodebuild -target Ghostty-iOS "CODE_SIGNING_ALLOWED=NO"
build-macos-tahoe:
build-macos-matrix:
runs-on: namespace-profile-ghostty-macos-tahoe
needs: test
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
# TODO(tahoe): https://github.com/NixOS/nix/issues/13342
- uses: DeterminateSystems/nix-installer-action@main
@@ -333,45 +333,8 @@ jobs:
- name: Xcode Select
run: sudo xcode-select -s /Applications/Xcode_26.0.app
- name: get the Zig deps
id: deps
run: nix build -L .#deps && echo "deps=$(readlink ./result)" >> $GITHUB_OUTPUT
# GhosttyKit is the framework that is built from Zig for our native
# Mac app to access.
- name: Build GhosttyKit
run: nix develop -c zig build --system ${{ steps.deps.outputs.deps }} -Demit-macos-app=false
# The native app is built with native Xcode tooling. This also does
# codesigning. IMPORTANT: this must NOT run in a Nix environment.
# Nix breaks xcodebuild so this has to be run outside.
- name: Build Ghostty.app
run: cd macos && xcodebuild -target Ghostty
# Build the iOS target without code signing just to verify it works.
- name: Build Ghostty iOS
run: |
cd macos
xcodebuild -target Ghostty-iOS "CODE_SIGNING_ALLOWED=NO"
build-macos-matrix:
runs-on: namespace-profile-ghostty-macos-sequoia
needs: test
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: Xcode Select
run: sudo xcode-select -s /Applications/Xcode_26.0.app
- name: Xcode Version
run: xcodebuild -version
- name: get the Zig deps
id: deps
@@ -400,13 +363,14 @@ jobs:
os:
[namespace-profile-ghostty-snap, namespace-profile-ghostty-snap-arm64]
runs-on: ${{ matrix.os }}
timeout-minutes: 45
needs: [test, build-dist]
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Download Source Tarball Artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: source-tarball
- name: Extract tarball
@@ -414,7 +378,7 @@ jobs:
mkdir dist
tar --verbose --extract --strip-components 1 --directory dist --file ghostty-source.tar.gz
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
@@ -434,10 +398,11 @@ jobs:
runs-on: windows-2022
# this will not stop other jobs from running
continue-on-error: true
timeout-minutes: 45
needs: test
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
# This could be from a script if we wanted to but inlining here for now
# in one place.
@@ -506,17 +471,17 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -551,17 +516,17 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -600,17 +565,17 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -648,17 +613,17 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -671,16 +636,16 @@ jobs:
nix develop -c zig build -Dsentry=${{ matrix.sentry }}
test-macos:
runs-on: namespace-profile-ghostty-macos-sequoia
runs-on: namespace-profile-ghostty-macos-tahoe
needs: test
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
# TODO(tahoe): https://github.com/NixOS/nix/issues/13342
- uses: DeterminateSystems/nix-installer-action@main
with:
nix_path: nixpkgs=channel:nixos-unstable
determinate: true
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
@@ -689,6 +654,9 @@ jobs:
- name: Xcode Select
run: sudo xcode-select -s /Applications/Xcode_26.0.app
- name: Xcode Version
run: xcodebuild -version
- name: get the Zig deps
id: deps
run: nix build -L .#deps && echo "deps=$(readlink ./result)" >> $GITHUB_OUTPUT
@@ -704,14 +672,14 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -732,14 +700,14 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -759,14 +727,14 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -786,14 +754,14 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -813,14 +781,14 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -840,14 +808,14 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -874,14 +842,14 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -901,14 +869,14 @@ jobs:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -935,17 +903,17 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -957,8 +925,8 @@ jobs:
run: |
nix develop -c sh -c "cd pkg/${{ matrix.pkg }} ; zig build test"
test-debian-12:
name: Test build on Debian 12
test-debian-13:
name: Test build on Debian 13
runs-on: namespace-profile-ghostty-sm
needs: [test, build-dist]
steps:
@@ -969,7 +937,7 @@ jobs:
uses: namespacelabs/nscloud-setup-buildx-action@01628ae51ea5d6b0c90109c7dccbf511953aff29 # v0.0.18
- name: Download Source Tarball Artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: source-tarball
@@ -984,34 +952,7 @@ jobs:
context: dist
file: dist/src/build/docker/debian/Dockerfile
build-args: |
DISTRO_VERSION=12
flatpak-check-zig-cache:
if: github.repository == 'ghostty-org/ghostty'
runs-on: namespace-profile-ghostty-xsm
env:
ZIG_LOCAL_CACHE_DIR: /zig/local-cache
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
with:
path: |
/nix
/zig
- name: Setup Nix
uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
useDaemon: false # sometimes fails on short jobs
- name: Check Flatpak Zig Dependencies
run: nix develop -c ./flatpak/build-support/check-zig-cache.sh
DISTRO_VERSION=13
flatpak:
if: github.repository == 'ghostty-org/ghostty'
@@ -1028,9 +969,9 @@ jobs:
- arch: aarch64
runner: namespace-profile-ghostty-md-arm64
runs-on: ${{ matrix.variant.runner }}
needs: [flatpak-check-zig-cache, test]
needs: test
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: flatpak/flatpak-github-actions/flatpak-builder@10a3c29f0162516f0f68006be14c92f34bd4fa6c # v6.5
with:
bundle: com.mitchellh.ghostty
@@ -1038,3 +979,94 @@ jobs:
cache-key: flatpak-builder-${{ github.sha }}
arch: ${{ matrix.variant.arch }}
verbose: true
valgrind:
if: github.repository == 'ghostty-org/ghostty'
runs-on: namespace-profile-ghostty-lg
timeout-minutes: 30
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@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
# Install Nix and use that to run our tests so our environment matches exactly.
- uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
with:
name: ghostty
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
- name: valgrind deps
run: |
sudo apt update -y
sudo apt install -y valgrind libc6-dbg
- name: valgrind
run: |
nix develop -c zig build test-valgrind
build-freebsd:
name: Build on FreeBSD
needs: test
runs-on: namespace-profile-mitchellh-sm-systemd
strategy:
matrix:
release:
- "14.3"
# - "15.0" # disable until fixed: https://github.com/vmactions/freebsd-vm/issues/108
steps:
- name: Checkout Ghostty
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Start SSH
run: |
sudo systemctl start ssh
- name: Set up FreeBSD VM
uses: vmactions/freebsd-vm@05856381fab64eeee9b038a0818f6cec649ca17a # v1.2.3
with:
release: ${{ matrix.release }}
copyback: false
usesh: true
prepare: |
pkg install -y \
devel/blueprint-compiler \
devel/gettext \
devel/git \
devel/pkgconf \
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
run: |
zig env
- name: Run tests
shell: freebsd {0}
run: |
cd $GITHUB_WORKSPACE
zig build test
- name: Build GTK-NG app runtime
shell: freebsd {0}
run: |
cd $GITHUB_WORKSPACE
zig build
./zig-out/bin/ghostty +version

View File

@@ -17,19 +17,19 @@ jobs:
ZIG_GLOBAL_CACHE_DIR: /zig/global-cache
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
- name: Setup Cache
uses: namespacelabs/nscloud-cache-action@9ff6d4004df1c3fd97cecafe010c874d77c48599 # v1.2.13
uses: namespacelabs/nscloud-cache-action@a289cf5d2fcd6874376aa92f0ef7f99dc923592a # v1.2.17
with:
path: |
/nix
/zig
- name: Setup Nix
uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1
uses: cachix/install-nix-action@56a7bb7b56d9a92d4fd1bc05758de7eea4a370a8 # v31.6.0
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16
@@ -50,8 +50,6 @@ jobs:
if ! git diff --exit-code build.zig.zon; then
nix develop -c ./nix/build-support/check-zig-cache.sh --update
nix develop -c ./nix/build-support/check-zig-cache.sh
nix develop -c ./flatpak/build-support/check-zig-cache.sh --update
nix develop -c ./flatpak/build-support/check-zig-cache.sh
fi
# Verify the build still works. We choose an arbitrary build type

2
.gitignore vendored
View File

@@ -21,3 +21,5 @@ glad.zip
/Box_test.ppm
/Box_test_diff.ppm
/ghostty.qcow2
vgcore.*

View File

@@ -169,6 +169,7 @@
/po/es_BO.UTF-8.po @ghostty-org/es_BO
/po/es_AR.UTF-8.po @ghostty-org/es_AR
/po/fr_FR.UTF-8.po @ghostty-org/fr_FR
/po/hu_HU.UTF-8.po @ghostty-org/hu_HU
/po/id_ID.UTF-8.po @ghostty-org/id_ID
/po/ja_JP.UTF-8.po @ghostty-org/ja_JP
/po/mk_MK.UTF-8.po @ghostty-org/mk_MK

View File

@@ -1,9 +1,9 @@
# Ghostty Development Process
# Contributing to Ghostty
This document describes the development process for Ghostty. It is intended for
anyone considering opening an **issue** or **pull request**. If in doubt,
please open a [discussion](https://github.com/ghostty-org/ghostty/discussions);
we can always convert that to an issue later.
This document describes the process of contributing to Ghostty. It is intended
for anyone considering opening an **issue**, **discussion** or **pull request**.
For people who are interested in developing Ghostty and technical details behind
it, please check out our ["Developing Ghostty"](HACKING.md) document as well.
> [!NOTE]
>
@@ -13,15 +13,52 @@ we can always convert that to an issue later.
> time to fixing bugs, maintaining features, and reviewing code, I do kindly
> ask you spend a few minutes reading this document. Thank you. ❤️
## AI Assistance Notice
> [!IMPORTANT]
>
> If you are using **any kind of AI assistance** to contribute to Ghostty,
> it must be disclosed in the pull request.
If you are using any kind of AI assistance while contributing to Ghostty,
**this must be disclosed in the pull request**, along with the extent to
which AI assistance was used (e.g. docs only vs. code generation).
If PR responses are being generated by an AI, disclose that as well.
As a small exception, trivial tab-completion doesn't need to be disclosed,
so long as it is limited to single keywords or short phrases.
An example disclosure:
> This PR was written primarily by Claude Code.
Or a more detailed disclosure:
> I consulted ChatGPT to understand the codebase but the solution
> was fully authored manually by myself.
Failure to disclose this is first and foremost rude to the human operators
on the other end of the pull request, but it also makes it difficult to
determine how much scrutiny to apply to the contribution.
In a perfect world, AI assistance would produce equal or higher quality
work than any human. That isn't the world we live in today, and in most cases
it's generating slop. I say this despite being a fan of and using them
successfully myself (with heavy supervision)!
Please be respectful to maintainers and disclose AI assistance.
## Quick Guide
**I'd like to contribute!**
### I'd like to contribute!
All issues are actionable. Pick one and start working on it. Thank you.
If you need help or guidance, comment on the issue. Issues that are extra
friendly to new contributors are tagged with "contributor friendly".
[All issues are actionable](#issues-are-actionable). Pick one and start
working on it. Thank you. If you need help or guidance, comment on the issue.
Issues that are extra friendly to new contributors are tagged with
["contributor friendly"].
**I'd like to translate Ghostty to my language!**
["contributor friendly"]: https://github.com/ghostty-org/ghostty/issues?q=is%3Aissue%20is%3Aopen%20label%3A%22contributor%20friendly%22
### I'd like to translate Ghostty to my language!
We have written a [Translator's Guide](po/README_TRANSLATORS.md) for
everyone interested in contributing translations to Ghostty.
@@ -30,25 +67,39 @@ and you can submit pull requests directly, although please make sure that
our [Style Guide](po/README_TRANSLATORS.md#style-guide) is followed before
submission.
**I have a bug!**
### I have a bug! / Something isn't working!
1. Search the issue tracker and discussions for similar issues.
2. If you don't have steps to reproduce, open a discussion.
3. If you have steps to reproduce, open an issue.
1. Search the issue tracker and discussions for similar issues. Tip: also
search for [closed issues] and [discussions] — your issue might have already
been fixed!
2. If your issue hasn't been reported already, open an ["Issue Triage" discussion]
and make sure to fill in the template **completely**. They are vital for
maintainers to figure out important details about your setup. Because of
this, please make sure that you _only_ use the "Issue Triage" category for
reporting bugs — thank you!
**I have an idea for a feature!**
[closed issues]: https://github.com/ghostty-org/ghostty/issues?q=is%3Aissue%20state%3Aclosed
[discussions]: https://github.com/ghostty-org/ghostty/discussions?discussions_q=is%3Aclosed
["Issue Triage" discussion]: https://github.com/ghostty-org/ghostty/discussions/new?category=issue-triage
1. Open a discussion.
### I have an idea for a feature!
**I've implemented a feature!**
Open a discussion in the ["Feature Requests, Ideas" category](https://github.com/ghostty-org/ghostty/discussions/new?category=feature-requests-ideas).
1. If there is an issue for the feature, open a pull request.
### I've implemented a feature!
1. If there is an issue for the feature, open a pull request straight away.
2. If there is no issue, open a discussion and link to your branch.
3. If you want to live dangerously, open a pull request and hope for the best.
3. If you want to live dangerously, open a pull request and
[hope for the best](#pull-requests-implement-an-issue).
**I have a question!**
### I have a question!
1. Open a discussion or use Discord.
Open an [Q&A discussion], or join our [Discord Server] and ask away in the
`#help` channel.
[Q&A discussion]: https://github.com/ghostty-org/ghostty/discussions/new?category=q-a
[Discord Server]: https://discord.gg/ghostty
## General Patterns
@@ -86,187 +137,3 @@ pull request will be accepted with a high degree of certainty.
> **Pull requests are NOT a place to discuss feature design.** Please do
> not open a WIP pull request to discuss a feature. Instead, use a discussion
> and link to your branch.
# Developer Guide
> [!NOTE]
>
> **The remainder of this file is dedicated to developers actively
> working on Ghostty.** If you're a user reporting an issue, you can
> ignore the rest of this document.
## Including and Updating Translations
See the [Contributor's Guide](po/README_CONTRIBUTORS.md) for more details.
## Input Stack Testing
The input stack is the part of the codebase that starts with a
key event and ends with text encoding being sent to the pty (it
does not include _rendering_ the text, which is part of the
font or rendering stack).
If you modify any part of the input stack, you must manually verify
all the following input cases work properly. We unfortunately do
not automate this in any way, but if we can do that one day that'd
save a LOT of grief and time.
Note: this list may not be exhaustive, I'm still working on it.
### Linux IME
IME (Input Method Editors) are a common source of bugs in the input stack,
especially on Linux since there are multiple different IME systems
interacting with different windowing systems and application frameworks
all written by different organizations.
The following matrix should be tested to ensure that all IME input works
properly:
1. Wayland, X11
2. ibus, fcitx, none
3. Dead key input (e.g. Spanish), CJK (e.g. Japanese), Emoji, Unicode Hex
4. ibus versions: 1.5.29, 1.5.30, 1.5.31 (each exhibit slightly different behaviors)
> [!NOTE]
>
> This is a **work in progress**. I'm still working on this list and it
> is not complete. As I find more test cases, I will add them here.
#### Dead Key Input
Set your keyboard layout to "Spanish" (or another layout that uses dead keys).
1. Launch Ghostty
2. Press `'`
3. Press `a`
4. Verify that `á` is displayed
Note that the dead key may or may not show a preedit state visually.
For ibus and fcitx it does but for the "none" case it does not. Importantly,
the text should be correct when it is sent to the pty.
We should also test canceling dead key input:
1. Launch Ghostty
2. Press `'`
3. Press escape
4. Press `a`
5. Verify that `a` is displayed (no diacritic)
#### CJK Input
Configure fcitx or ibus with a keyboard layout like Japanese or Mozc. The
exact layout doesn't matter.
1. Launch Ghostty
2. Press `Ctrl+Shift` to switch to "Hiragana"
3. On a US physical layout, type: `konn`, you should see `こん` in preedit.
4. Press `Enter`
5. Verify that `こん` is displayed in the terminal.
We should also test switching input methods while preedit is active, which
should commit the text:
1. Launch Ghostty
2. Press `Ctrl+Shift` to switch to "Hiragana"
3. On a US physical layout, type: `konn`, you should see `こん` in preedit.
4. Press `Ctrl+Shift` to switch to another layout (any)
5. Verify that `こん` is displayed in the terminal as committed text.
## Nix Virtual Machines
Several Nix virtual machine definitions are provided by the project for testing
and developing Ghostty against multiple different Linux desktop environments.
Running these requires a working Nix installation, either Nix on your
favorite Linux distribution, NixOS, or macOS with nix-darwin installed. Further
requirements for macOS are detailed below.
VMs should only be run on your local desktop and then powered off when not in
use, which will discard any changes to the VM.
The VM definitions provide minimal software "out of the box" but additional
software can be installed by using standard Nix mechanisms like `nix run nixpkgs#<package>`.
### Linux
1. Check out the Ghostty source and change to the directory.
2. Run `nix run .#<vmtype>`. `<vmtype>` can be any of the VMs defined in the
`nix/vm` directory (without the `.nix` suffix) excluding any file prefixed
with `common` or `create`.
3. The VM will build and then launch. Depending on the speed of your system, this
can take a while, but eventually you should get a new VM window.
4. The Ghostty source directory should be mounted to `/tmp/shared` in the VM. Depending
on what UID and GID of the user that you launched the VM as, `/tmp/shared` _may_ be
writable by the VM user, so be careful!
### macOS
1. To run the VMs on macOS you will need to enable the Linux builder in your `nix-darwin`
config. This _should_ be as simple as adding `nix.linux-builder.enable=true` to your
configuration and then rebuilding. See [this](https://nixcademy.com/posts/macos-linux-builder/)
blog post for more information about the Linux builder and how to tune the performance.
2. Once the Linux builder has been enabled, you should be able to follow the Linux instructions
above to launch a VM.
### Custom VMs
To easily create a custom VM without modifying the Ghostty source, create a new
directory, then create a file called `flake.nix` with the following text in the
new directory.
```
{
inputs = {
nixpkgs.url = "nixpkgs/nixpkgs-unstable";
ghostty.url = "github:ghostty-org/ghostty";
};
outputs = {
nixpkgs,
ghostty,
...
}: {
nixosConfigurations.custom-vm = ghostty.create-gnome-vm {
nixpkgs = nixpkgs;
system = "x86_64-linux";
overlay = ghostty.overlays.releasefast;
# module = ./configuration.nix # also works
module = {pkgs, ...}: {
environment.systemPackages = [
pkgs.btop
];
};
};
};
}
```
The custom VM can then be run with a command like this:
```
nix run .#nixosConfigurations.custom-vm.config.system.build.vm
```
A file named `ghostty.qcow2` will be created that is used to persist any changes
made in the VM. To "reset" the VM to default delete the file and it will be
recreated the next time you run the VM.
### Contributing new VM definitions
#### VM Acceptance Criteria
We welcome the contribution of new VM definitions, as long as they meet the following criteria:
1. The should be different enough from existing VM definitions that they represent a distinct
user (and developer) experience.
2. There's a significant Ghostty user population that uses a similar environment.
3. The VMs can be built using only packages from the current stable NixOS release.
#### VM Definition Criteria
1. VMs should be as minimal as possible so that they build and launch quickly.
Additional software can be added at runtime with a command like `nix run nixpkgs#<package name>`.
2. VMs should not expose any services to the network, or run any remote access
software like SSH daemons, VNC or RDP.
3. VMs should auto-login using the "ghostty" user.

329
HACKING.md Normal file
View File

@@ -0,0 +1,329 @@
# Developing Ghostty
This document describes the technical details behind Ghostty's development.
If you'd like to open any pull requests or would like to implement new features
into Ghostty, please make sure to read our ["Contributing to Ghostty"](CONTRIBUTING.md)
document first.
To start development on Ghostty, you need to build Ghostty from a Git checkout,
which is very similar in process to [building Ghostty from a source tarball](http://ghostty.org/docs/install/build). One key difference is that obviously
you need to clone the Git repository instead of unpacking the source tarball:
```shell
git clone https://github.com/ghostty-org/ghostty
cd ghostty
```
> [!NOTE]
>
> Ghostty may require [extra dependencies](#extra-dependencies)
> when building from a Git checkout compared to a source tarball.
> Tip versions may also require a different version of Zig or other toolchains
> (e.g. the Xcode SDK on macOS) compared to stable versions — make sure to
> follow the steps closely!
When you're developing Ghostty, it's very likely that you will want to build a
_debug_ build to diagnose issues more easily. This is already the default for
Zig builds, so simply run `zig build` **without any `-Doptimize` flags**.
There are many more build steps than just `zig build`, some of which are listed
here:
| Command | Description |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `zig build run` | Runs Ghostty |
| `zig build run-valgrind` | Runs Ghostty under Valgrind to [check for memory leaks](#checking-for-memory-leaks) |
| `zig build test` | Runs unit tests (accepts `-Dtest-filter=<filter>` to only run tests whose name matches the filter) |
| `zig build update-translations` | Updates Ghostty's translation strings (see the [Contributor's Guide on Localizing Ghostty](po/README_CONTRIBUTORS.md)) |
| `zig build dist` | Builds a source tarball |
| `zig build distcheck` | Installs and validates a source tarball |
## Extra Dependencies
Building Ghostty from a Git checkout on Linux requires some additional
dependencies:
- `blueprint-compiler` (version 0.16.0 or newer)
macOS users don't require any additional dependencies.
## Xcode Version and SDKs
Building the Ghostty macOS app requires that Xcode, the macOS SDK,
and the iOS SDK are all installed.
A common issue is that the incorrect version of Xcode is either
installed or selected. Use the `xcode-select` command to
ensure that the correct version of Xcode is selected:
```shell-session
sudo xcode-select --switch /Applications/Xcode-beta.app
```
> [!IMPORTANT]
>
> Main branch development of Ghostty is preparing for the next major
> macOS release, Tahoe (macOS 26). Therefore, the main branch requires
> **Xcode 26 and the macOS 26 SDK**.
>
> You do not need to be running on macOS 26 to build Ghostty, you can
> still use Xcode 26 beta on macOS 15 stable.
## Linting
### Prettier
Ghostty's docs and resources (not including Zig code) are linted using
[Prettier](https://prettier.io) with out-of-the-box settings. A Prettier CI
check will fail builds with improper formatting. Therefore, if you are
modifying anything Prettier will lint, you may want to install it locally and
run this from the repo root before you commit:
```
prettier --write .
```
Make sure your Prettier version matches the version of Prettier in [devShell.nix](https://github.com/ghostty-org/ghostty/blob/main/nix/devShell.nix).
Nix users can use the following command to format with Prettier:
```
nix develop -c prettier --write .
```
### Alejandra
Nix modules are formatted with [Alejandra](https://github.com/kamadorueda/alejandra/). An Alejandra CI check
will fail builds with improper formatting.
Nix users can use the following command to format with Alejandra:
```
nix develop -c alejandra .
```
Non-Nix users should install Alejandra and use the following command to format with Alejandra:
```
alejandra .
```
Make sure your Alejandra version matches the version of Alejandra in [devShell.nix](https://github.com/ghostty-org/ghostty/blob/main/nix/devShell.nix).
### Updating the Zig Cache Fixed-Output Derivation Hash
The Nix package depends on a [fixed-output
derivation](https://nix.dev/manual/nix/stable/language/advanced-attributes.html#adv-attr-outputHash)
that manages the Zig package cache. This allows the package to be built in the
Nix sandbox.
Occasionally (usually when `build.zig.zon` is updated), the hash that
identifies the cache will need to be updated. There are jobs that monitor the
hash in CI, and builds will fail if it drifts.
To update it, you can run the following in the repository root:
```
./nix/build-support/check-zig-cache-hash.sh --update
```
This will write out the `nix/zigCacheHash.nix` file with the updated hash
that can then be committed and pushed to fix the builds.
## Including and Updating Translations
See the [Contributor's Guide](po/README_CONTRIBUTORS.md) for more details.
## Checking for Memory Leaks
While Zig does an amazing job of finding and preventing memory leaks,
Ghostty uses many third-party libraries that are written in C. Improper usage
of those libraries or bugs in those libraries can cause memory leaks that
Zig cannot detect by itself.
### On Linux
On Linux the recommended tool to check for memory leaks is Valgrind. The
recommended way to run Valgrind is via `zig build`:
```sh
zig build run-valgrind
```
This builds a Ghostty executable with Valgrind support and runs Valgrind
with the proper flags to ensure we're suppressing known false positives.
You can combine the same build args with `run-valgrind` that you can with
`run`, such as specifying additional configurations after a trailing `--`.
## Input Stack Testing
The input stack is the part of the codebase that starts with a
key event and ends with text encoding being sent to the pty (it
does not include _rendering_ the text, which is part of the
font or rendering stack).
If you modify any part of the input stack, you must manually verify
all the following input cases work properly. We unfortunately do
not automate this in any way, but if we can do that one day that'd
save a LOT of grief and time.
Note: this list may not be exhaustive, I'm still working on it.
### Linux IME
IME (Input Method Editors) are a common source of bugs in the input stack,
especially on Linux since there are multiple different IME systems
interacting with different windowing systems and application frameworks
all written by different organizations.
The following matrix should be tested to ensure that all IME input works
properly:
1. Wayland, X11
2. ibus, fcitx, none
3. Dead key input (e.g. Spanish), CJK (e.g. Japanese), Emoji, Unicode Hex
4. ibus versions: 1.5.29, 1.5.30, 1.5.31 (each exhibit slightly different behaviors)
> [!NOTE]
>
> This is a **work in progress**. I'm still working on this list and it
> is not complete. As I find more test cases, I will add them here.
#### Dead Key Input
Set your keyboard layout to "Spanish" (or another layout that uses dead keys).
1. Launch Ghostty
2. Press `'`
3. Press `a`
4. Verify that `á` is displayed
Note that the dead key may or may not show a preedit state visually.
For ibus and fcitx it does but for the "none" case it does not. Importantly,
the text should be correct when it is sent to the pty.
We should also test canceling dead key input:
1. Launch Ghostty
2. Press `'`
3. Press escape
4. Press `a`
5. Verify that `a` is displayed (no diacritic)
#### CJK Input
Configure fcitx or ibus with a keyboard layout like Japanese or Mozc. The
exact layout doesn't matter.
1. Launch Ghostty
2. Press `Ctrl+Shift` to switch to "Hiragana"
3. On a US physical layout, type: `konn`, you should see `こん` in preedit.
4. Press `Enter`
5. Verify that `こん` is displayed in the terminal.
We should also test switching input methods while preedit is active, which
should commit the text:
1. Launch Ghostty
2. Press `Ctrl+Shift` to switch to "Hiragana"
3. On a US physical layout, type: `konn`, you should see `こん` in preedit.
4. Press `Ctrl+Shift` to switch to another layout (any)
5. Verify that `こん` is displayed in the terminal as committed text.
## Nix Virtual Machines
Several Nix virtual machine definitions are provided by the project for testing
and developing Ghostty against multiple different Linux desktop environments.
Running these requires a working Nix installation, either Nix on your
favorite Linux distribution, NixOS, or macOS with nix-darwin installed. Further
requirements for macOS are detailed below.
VMs should only be run on your local desktop and then powered off when not in
use, which will discard any changes to the VM.
The VM definitions provide minimal software "out of the box" but additional
software can be installed by using standard Nix mechanisms like `nix run nixpkgs#<package>`.
### Linux
1. Check out the Ghostty source and change to the directory.
2. Run `nix run .#<vmtype>`. `<vmtype>` can be any of the VMs defined in the
`nix/vm` directory (without the `.nix` suffix) excluding any file prefixed
with `common` or `create`.
3. The VM will build and then launch. Depending on the speed of your system, this
can take a while, but eventually you should get a new VM window.
4. The Ghostty source directory should be mounted to `/tmp/shared` in the VM. Depending
on what UID and GID of the user that you launched the VM as, `/tmp/shared` _may_ be
writable by the VM user, so be careful!
### macOS
1. To run the VMs on macOS you will need to enable the Linux builder in your `nix-darwin`
config. This _should_ be as simple as adding `nix.linux-builder.enable=true` to your
configuration and then rebuilding. See [this](https://nixcademy.com/posts/macos-linux-builder/)
blog post for more information about the Linux builder and how to tune the performance.
2. Once the Linux builder has been enabled, you should be able to follow the Linux instructions
above to launch a VM.
### Custom VMs
To easily create a custom VM without modifying the Ghostty source, create a new
directory, then create a file called `flake.nix` with the following text in the
new directory.
```
{
inputs = {
nixpkgs.url = "nixpkgs/nixpkgs-unstable";
ghostty.url = "github:ghostty-org/ghostty";
};
outputs = {
nixpkgs,
ghostty,
...
}: {
nixosConfigurations.custom-vm = ghostty.create-gnome-vm {
nixpkgs = nixpkgs;
system = "x86_64-linux";
overlay = ghostty.overlays.releasefast;
# module = ./configuration.nix # also works
module = {pkgs, ...}: {
environment.systemPackages = [
pkgs.btop
];
};
};
};
}
```
The custom VM can then be run with a command like this:
```
nix run .#nixosConfigurations.custom-vm.config.system.build.vm
```
A file named `ghostty.qcow2` will be created that is used to persist any changes
made in the VM. To "reset" the VM to default delete the file and it will be
recreated the next time you run the VM.
### Contributing new VM definitions
#### VM Acceptance Criteria
We welcome the contribution of new VM definitions, as long as they meet the following criteria:
1. They should be different enough from existing VM definitions that they represent a distinct
user (and developer) experience.
2. There's a significant Ghostty user population that uses a similar environment.
3. The VMs can be built using only packages from the current stable NixOS release.
#### VM Definition Criteria
1. VMs should be as minimal as possible so that they build and launch quickly.
Additional software can be added at runtime with a command like `nix run nixpkgs#<package name>`.
2. VMs should not expose any services to the network, or run any remote access
software like SSH daemons, VNC or RDP.
3. VMs should auto-login using the "ghostty" user.

128
README.md
View File

@@ -13,7 +13,9 @@
·
<a href="https://ghostty.org/docs">Documentation</a>
·
<a href="#developing-ghostty">Developing</a>
<a href="CONTRIBUTING.md">Contributing</a>
·
<a href="HACKING.md">Developing</a>
</p>
</p>
@@ -49,6 +51,14 @@ See the [download page](https://ghostty.org/download) on the Ghostty website.
See the [documentation](https://ghostty.org/docs) on the Ghostty website.
## Contributing and Developing
If you have any ideas, issues, etc. regarding Ghostty, or would like to
contribute to Ghostty through pull requests, please check out our
["Contributing to Ghostty"](CONTRIBUTING.md) document. Those who would like
to get involved with Ghostty's development as well should also read the
["Developing Ghostty"](HACKING.md) document for more technical details.
## Roadmap and Status
The high-level ambitious plan for the project, in order:
@@ -184,119 +194,3 @@ SENTRY_DSN=https://e914ee84fd895c4fe324afa3e53dac76@o4507352570920960.ingest.us.
> stack memory of each thread at the time of the crash. This information
> is used to rebuild the stack trace but can also contain sensitive data
> depending when the crash occurred.
## Developing Ghostty
See the documentation on the Ghostty website for
[building Ghostty from a source tarball](http://ghostty.org/docs/install/build).
Building Ghostty from a Git checkout is very similar, except you want to
omit the `-Doptimize` flag to build a debug build, and you may require
additional dependencies since the source tarball includes some processed
files that are not in the Git repository.
Other useful commands:
- `zig build test` for running unit tests.
- `zig build test -Dtest-filter=<filter>` for running a specific subset of those unit tests
- `zig build run -Dconformance=<name>` runs a conformance test case from
the `conformance` directory. The `name` is the name of the file. This runs
in the current running terminal emulator so if you want to check the
behavior of this project, you must run this command in Ghostty.
### Extra Dependencies
Building Ghostty from a Git checkout on Linux requires some additional
dependencies:
- `blueprint-compiler`
macOS users don't require any additional dependencies.
> [!NOTE]
> This only applies to building from a _Git checkout_. This section does
> not apply if you're building from a released _source tarball_. For
> source tarballs, see the
> [website](http://ghostty.org/docs/install/build).
### Xcode Version and SDKs
Building the Ghostty macOS app requires that Xcode, the macOS SDK,
and the iOS SDK are all installed.
A common issue is that the incorrect version of Xcode is either
installed or selected. Use the `xcode-select` command to
ensure that the correct version of Xcode is selected:
```shell-session
sudo xcode-select --switch /Applications/Xcode-beta.app
```
> [!IMPORTANT]
>
> Main branch development of Ghostty is preparing for the next major
> macOS release, Tahoe (macOS 26). Therefore, the main branch requires
> **Xcode 26 and the macOS 26 SDK**.
>
> You do not need to be running on macOS 26 to build Ghostty, you can
> still use Xcode 26 beta on macOS 15 stable.
### Linting
#### Prettier
Ghostty's docs and resources (not including Zig code) are linted using
[Prettier](https://prettier.io) with out-of-the-box settings. A Prettier CI
check will fail builds with improper formatting. Therefore, if you are
modifying anything Prettier will lint, you may want to install it locally and
run this from the repo root before you commit:
```
prettier --write .
```
Make sure your Prettier version matches the version of Prettier in [devShell.nix](https://github.com/ghostty-org/ghostty/blob/main/nix/devShell.nix).
Nix users can use the following command to format with Prettier:
```
nix develop -c prettier --write .
```
#### Alejandra
Nix modules are formatted with [Alejandra](https://github.com/kamadorueda/alejandra/). An Alejandra CI check
will fail builds with improper formatting.
Nix users can use the following command to format with Alejandra:
```
nix develop -c alejandra .
```
Non-Nix users should install Alejandra and use the following command to format with Alejandra:
```
alejandra .
```
Make sure your Alejandra version matches the version of Alejandra in [devShell.nix](https://github.com/ghostty-org/ghostty/blob/main/nix/devShell.nix).
#### Updating the Zig Cache Fixed-Output Derivation Hash
The Nix package depends on a [fixed-output
derivation](https://nix.dev/manual/nix/stable/language/advanced-attributes.html#adv-attr-outputHash)
that manages the Zig package cache. This allows the package to be built in the
Nix sandbox.
Occasionally (usually when `build.zig.zon` is updated), the hash that
identifies the cache will need to be updated. There are jobs that monitor the
hash in CI, and builds will fail if it drifts.
To update it, you can run the following in the repository root:
```
./nix/build-support/check-zig-cache-hash.sh --update
```
This will write out the `nix/zigCacheHash.nix` file with the updated hash
that can then be committed and pushed to fix the builds.

View File

@@ -19,7 +19,15 @@ pub fn build(b: *std.Build) !void {
// All our steps which we'll hook up later. The steps are shown
// up here just so that they are more self-documenting.
const run_step = b.step("run", "Run the app");
const test_step = b.step("test", "Run all tests");
const run_valgrind_step = b.step(
"run-valgrind",
"Run the app under valgrind",
);
const test_step = b.step("test", "Run tests");
const test_valgrind_step = b.step(
"test-valgrind",
"Run tests under valgrind",
);
const translations_step = b.step(
"update-translations",
"Update translation files",
@@ -27,7 +35,7 @@ pub fn build(b: *std.Build) !void {
// Ghostty resources like terminfo, shell integration, themes, etc.
const resources = try buildpkg.GhosttyResources.init(b, &config);
const i18n = try buildpkg.GhosttyI18n.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);
@@ -77,9 +85,11 @@ pub fn build(b: *std.Build) !void {
// Runtime "none" is libghostty, anything else is an executable.
if (config.app_runtime != .none) {
exe.install();
resources.install();
i18n.install();
if (config.emit_exe) {
exe.install();
resources.install();
if (i18n) |v| v.install();
}
} else {
// Libghostty
//
@@ -112,7 +122,7 @@ pub fn build(b: *std.Build) !void {
// The xcframework build always installs resources because our
// macOS xcode project contains references to them.
resources.install();
i18n.install();
if (i18n) |v| v.install();
}
// Ghostty macOS app
@@ -122,7 +132,7 @@ pub fn build(b: *std.Build) !void {
.{
.xcframework = &xcframework,
.docs = &docs,
.i18n = &i18n,
.i18n = if (i18n) |v| &v else null,
.resources = &resources,
},
);
@@ -166,7 +176,7 @@ pub fn build(b: *std.Build) !void {
.{
.xcframework = &xcframework_native,
.docs = &docs,
.i18n = &i18n,
.i18n = if (i18n) |v| &v else null,
.resources = &resources,
},
);
@@ -181,6 +191,31 @@ pub fn build(b: *std.Build) !void {
}
}
// Valgrind
if (config.app_runtime != .none) {
// We need to rebuild Ghostty with a baseline CPU target.
const valgrind_exe = exe: {
var valgrind_config = config;
valgrind_config.target = valgrind_config.baselineTarget();
break :exe try buildpkg.GhosttyExe.init(
b,
&valgrind_config,
&deps,
);
};
const run_cmd = b.addSystemCommand(&.{
"valgrind",
"--leak-check=full",
"--num-callers=50",
b.fmt("--suppressions={s}", .{b.pathFromRoot("valgrind.supp")}),
"--gen-suppressions=all",
});
run_cmd.addArtifactArg(valgrind_exe.exe);
if (b.args) |args| run_cmd.addArgs(args);
run_valgrind_step.dependOn(&run_cmd.step);
}
// Tests
{
const test_exe = b.addTest(.{
@@ -188,7 +223,7 @@ pub fn build(b: *std.Build) !void {
.filters = if (test_filter) |v| &.{v} else &.{},
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = config.target,
.target = config.baselineTarget(),
.optimize = .Debug,
.strip = false,
.omit_frame_pointer = false,
@@ -198,11 +233,28 @@ pub fn build(b: *std.Build) !void {
if (config.emit_test_exe) b.installArtifact(test_exe);
_ = try deps.add(test_exe);
// Normal test running
const test_run = b.addRunArtifact(test_exe);
test_step.dependOn(&test_run.step);
// Valgrind test running
const valgrind_run = b.addSystemCommand(&.{
"valgrind",
"--leak-check=full",
"--num-callers=50",
b.fmt("--suppressions={s}", .{b.pathFromRoot("valgrind.supp")}),
"--gen-suppressions=all",
});
valgrind_run.addArtifactArg(test_exe);
test_valgrind_step.dependOn(&valgrind_run.step);
}
// update-translations does what it sounds like and updates the "pot"
// files. These should be committed to the repo.
translations_step.dependOn(i18n.update_step);
if (i18n) |v| {
translations_step.dependOn(v.update_step);
} else {
try translations_step.addError("cannot update translations when i18n is disabled", .{});
}
}

View File

@@ -20,8 +20,8 @@
},
.z2d = .{
// vancluever/z2d
.url = "https://github.com/vancluever/z2d/archive/8bbd035f4101f02b1d27947def0d7da3215df7fe.tar.gz",
.hash = "z2d-0.7.0-j5P_Hg_DDACq-2H2Zh7rAq6_TXWdQzv7JAUfnrdeDosg",
.url = "https://github.com/vancluever/z2d/archive/refs/tags/v0.7.2.tar.gz",
.hash = "z2d-0.7.2-j5P_Hm1oDQDQsWpGfSCMARhowBnuTHlQ_sBfij6TuG7l",
.lazy = true,
},
.zig_objc = .{
@@ -55,8 +55,8 @@
.gobject = .{
// https://github.com/jcollie/ghostty-gobject based on zig_gobject
// Temporary until we generate them at build time automatically.
.url = "https://github.com/jcollie/ghostty-gobject/releases/download/0.14.1-2025-07-19-27-1/ghostty-gobject-0.14.1-2025-07-19-27-1.tar.zst",
.hash = "gobject-0.3.0-Skun7KzYnAAsvbz0JzKA4LBdXbLqj0eNXHoKAIE0HkOl",
.url = "https://github.com/jcollie/ghostty-gobject/releases/download/0.14.1-2025-08-09-37-1/ghostty-gobject-0.14.1-2025-08-09-37-1.tar.zst",
.hash = "gobject-0.3.0-Skun7AngnABC2BPiaoobs6YSSzSgMuEIcjb2rYrRyaAM",
.lazy = true,
},
@@ -112,8 +112,8 @@
// Other
.apple_sdk = .{ .path = "./pkg/apple-sdk" },
.iterm2_themes = .{
.url = "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/92f20650771384b82f981fb0f249e5fbdcb69e9f.tar.gz",
.hash = "N-V-__8AAGHcWgSXHA9Fw-E0Hbe5EZWyYyI1AvW9O_HBbkRH",
.url = "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/6cdbc8501d48601302e32d6b53e9e7934bf354b4.tar.gz",
.hash = "N-V-__8AAAtjXwSdhZq_xYbCXo0SZMqoNoQuHFkC07sijQME",
.lazy = true,
},
},

18
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-Skun7KzYnAAsvbz0JzKA4LBdXbLqj0eNXHoKAIE0HkOl": {
"gobject-0.3.0-Skun7AngnABC2BPiaoobs6YSSzSgMuEIcjb2rYrRyaAM": {
"name": "gobject",
"url": "https://github.com/jcollie/ghostty-gobject/releases/download/0.14.1-2025-07-19-27-1/ghostty-gobject-0.14.1-2025-07-19-27-1.tar.zst",
"hash": "sha256-c4szPFC+L2H8ZQ3g7aoVi+lPmF4I6STxN9+fBhxaap8="
"url": "https://github.com/jcollie/ghostty-gobject/releases/download/0.14.1-2025-08-09-37-1/ghostty-gobject-0.14.1-2025-08-09-37-1.tar.zst",
"hash": "sha256-B0ziLzKud+kdKu5T1BTE9GMh8EPM/KhhhoNJlys5QPI="
},
"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-__8AAGHcWgSXHA9Fw-E0Hbe5EZWyYyI1AvW9O_HBbkRH": {
"N-V-__8AAAtjXwSdhZq_xYbCXo0SZMqoNoQuHFkC07sijQME": {
"name": "iterm2_themes",
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/92f20650771384b82f981fb0f249e5fbdcb69e9f.tar.gz",
"hash": "sha256-sQ5IWKQdEU3MOHzxovjA4DO6f/ryvtW18aITN4Bkog0="
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/6cdbc8501d48601302e32d6b53e9e7934bf354b4.tar.gz",
"hash": "sha256-NlUXcBOmaA8W+7RXuXcn9TIhm964dXO2Op4QCQxhDyc="
},
"N-V-__8AAIC5lwAVPJJzxnCAahSvZTIlG-HhtOvnM1uh-66x": {
"name": "jetbrains_mono",
@@ -129,10 +129,10 @@
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
"hash": "sha256-nkzSCr6W5sTG7enDBXEIhgEm574uLD41UVR2wlC+HBM="
},
"z2d-0.7.0-j5P_Hg_DDACq-2H2Zh7rAq6_TXWdQzv7JAUfnrdeDosg": {
"z2d-0.7.2-j5P_Hm1oDQDQsWpGfSCMARhowBnuTHlQ_sBfij6TuG7l": {
"name": "z2d",
"url": "https://github.com/vancluever/z2d/archive/8bbd035f4101f02b1d27947def0d7da3215df7fe.tar.gz",
"hash": "sha256-wfadegeixcbgxRzRtf6M2H34CTuvDM22XVIhuufFBG4="
"url": "https://github.com/vancluever/z2d/archive/refs/tags/v0.7.2.tar.gz",
"hash": "sha256-tWrLlEOU4/0ZOlzgGOXB08fW7sqfyAFf3rlv0wl9b/c="
},
"zf-0.10.3-OIRy8aiIAACLrBllz0zjxaH0aOe5oNm3KtEMyCntST-9": {
"name": "zf",

19
build.zig.zon.nix generated
View File

@@ -49,6 +49,7 @@
inherit name rev hash;
url = url_without_query;
deepClone = false;
fetchSubmodules = false;
};
fetchZigArtifact = {
@@ -122,11 +123,11 @@ in
};
}
{
name = "gobject-0.3.0-Skun7KzYnAAsvbz0JzKA4LBdXbLqj0eNXHoKAIE0HkOl";
name = "gobject-0.3.0-Skun7AngnABC2BPiaoobs6YSSzSgMuEIcjb2rYrRyaAM";
path = fetchZigArtifact {
name = "gobject";
url = "https://github.com/jcollie/ghostty-gobject/releases/download/0.14.1-2025-07-19-27-1/ghostty-gobject-0.14.1-2025-07-19-27-1.tar.zst";
hash = "sha256-c4szPFC+L2H8ZQ3g7aoVi+lPmF4I6STxN9+fBhxaap8=";
url = "https://github.com/jcollie/ghostty-gobject/releases/download/0.14.1-2025-08-09-37-1/ghostty-gobject-0.14.1-2025-08-09-37-1.tar.zst";
hash = "sha256-B0ziLzKud+kdKu5T1BTE9GMh8EPM/KhhhoNJlys5QPI=";
};
}
{
@@ -162,11 +163,11 @@ in
};
}
{
name = "N-V-__8AAGHcWgSXHA9Fw-E0Hbe5EZWyYyI1AvW9O_HBbkRH";
name = "N-V-__8AAAtjXwSdhZq_xYbCXo0SZMqoNoQuHFkC07sijQME";
path = fetchZigArtifact {
name = "iterm2_themes";
url = "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/92f20650771384b82f981fb0f249e5fbdcb69e9f.tar.gz";
hash = "sha256-sQ5IWKQdEU3MOHzxovjA4DO6f/ryvtW18aITN4Bkog0=";
url = "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/6cdbc8501d48601302e32d6b53e9e7934bf354b4.tar.gz";
hash = "sha256-NlUXcBOmaA8W+7RXuXcn9TIhm964dXO2Op4QCQxhDyc=";
};
}
{
@@ -290,11 +291,11 @@ in
};
}
{
name = "z2d-0.7.0-j5P_Hg_DDACq-2H2Zh7rAq6_TXWdQzv7JAUfnrdeDosg";
name = "z2d-0.7.2-j5P_Hm1oDQDQsWpGfSCMARhowBnuTHlQ_sBfij6TuG7l";
path = fetchZigArtifact {
name = "z2d";
url = "https://github.com/vancluever/z2d/archive/8bbd035f4101f02b1d27947def0d7da3215df7fe.tar.gz";
hash = "sha256-wfadegeixcbgxRzRtf6M2H34CTuvDM22XVIhuufFBG4=";
url = "https://github.com/vancluever/z2d/archive/refs/tags/v0.7.2.tar.gz";
hash = "sha256-tWrLlEOU4/0ZOlzgGOXB08fW7sqfyAFf3rlv0wl9b/c=";
};
}
{

6
build.zig.zon.txt generated
View File

@@ -27,9 +27,9 @@ https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d6
https://deps.files.ghostty.org/zig_js-12205a66d423259567764fa0fc60c82be35365c21aeb76c5a7dc99698401f4f6fefc.tar.gz
https://deps.files.ghostty.org/ziglyph-b89d43d1e3fb01b6074bc1f7fc980324b04d26a5.tar.gz
https://deps.files.ghostty.org/zlib-1220fed0c74e1019b3ee29edae2051788b080cd96e90d56836eea857b0b966742efb.tar.gz
https://github.com/jcollie/ghostty-gobject/releases/download/0.14.1-2025-07-19-27-1/ghostty-gobject-0.14.1-2025-07-19-27-1.tar.zst
https://github.com/mbadolato/iTerm2-Color-Schemes/archive/92f20650771384b82f981fb0f249e5fbdcb69e9f.tar.gz
https://github.com/jcollie/ghostty-gobject/releases/download/0.14.1-2025-08-09-37-1/ghostty-gobject-0.14.1-2025-08-09-37-1.tar.zst
https://github.com/mbadolato/iTerm2-Color-Schemes/archive/6cdbc8501d48601302e32d6b53e9e7934bf354b4.tar.gz
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/8bbd035f4101f02b1d27947def0d7da3215df7fe.tar.gz
https://github.com/vancluever/z2d/archive/refs/tags/v0.7.2.tar.gz

25
flake.lock generated
View File

@@ -47,6 +47,19 @@
"url": "https://channels.nixos.org/nixos-25.05/nixexprs.tar.xz"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1755972213,
"narHash": "sha256-VYK7aDAv8H1enXn1ECRHmGbeY6RqLnNwUJkOwloIsko=",
"rev": "73e96df7cff5783f45e21342a75a1540c4eddce4",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/unstable-small/nixos-25.11pre850642.73e96df7cff5/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
"url": "https://channels.nixos.org/nixos-unstable-small/nixexprs.tar.xz"
}
},
"root": {
"inputs": {
"flake-compat": "flake-compat",
@@ -102,22 +115,20 @@
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1742104771,
"narHash": "sha256-LhidlyEA9MP8jGe1rEnyjGFCzLLgCdDpYeWggibayr0=",
"lastModified": 1756000480,
"narHash": "sha256-fR5pdcjO0II5MNdCzqvyokyuFkmff7/FyBAjUS6sMfA=",
"owner": "jcollie",
"repo": "zon2nix",
"rev": "56c159be489cc6c0e73c3930bd908ddc6fe89613",
"rev": "d9dc9ef1ab9ae45b5c9d80c6a747cc9968ee0c60",
"type": "github"
},
"original": {
"owner": "jcollie",
"repo": "zon2nix",
"rev": "56c159be489cc6c0e73c3930bd908ddc6fe89613",
"rev": "d9dc9ef1ab9ae45b5c9d80c6a747cc9968ee0c60",
"type": "github"
}
}

View File

@@ -24,9 +24,12 @@
};
zon2nix = {
url = "github:jcollie/zon2nix?rev=56c159be489cc6c0e73c3930bd908ddc6fe89613";
url = "github:jcollie/zon2nix?rev=d9dc9ef1ab9ae45b5c9d80c6a747cc9968ee0c60";
inputs = {
nixpkgs.follows = "nixpkgs";
# Don't override nixpkgs until Zig 0.15 is available in the Nix branch
# we are using for "normal" builds.
#
# nixpkgs.follows = "nixpkgs";
flake-utils.follows = "flake-utils";
};
};

View File

@@ -1,108 +0,0 @@
#!/usr/bin/env bash
#
# This script checks if the flatpak/zig-packages.json file is up-to-date.
# If the `--update` flag is passed, it will update all necessary
# files to be up to date.
#
# The files owned by this are:
#
# - flatpak/zig-packages.json
#
# All of these are auto-generated and should not be edited manually.
# Nothing in this script should fail.
set -eu
set -o pipefail
WORK_DIR=$(mktemp -d)
if [[ ! "$WORK_DIR" || ! -d "$WORK_DIR" ]]; then
echo "could not create temp dir"
exit 1
fi
function cleanup {
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
help() {
echo ""
echo "To fix, please (manually) re-run the script from the repository root,"
echo "commit, and submit a PR with the update:"
echo ""
echo " ./flatpak/build-support/check-zig-cache.sh --update"
echo " git add flatpak/zig-packages.json"
echo " git commit -m \"flatpak: update zig-packages.json\""
echo ""
}
# Turn Nix's base64 hashes into regular hexadecimal form
decode_hash() {
input=$1
input=${input#sha256-}
echo "$input" | base64 -d | od -vAn -t x1 | tr -d ' \n'
}
ROOT="$(realpath "$(dirname "$0")/../../")"
ZIG_PACKAGES_JSON="$ROOT/flatpak/zig-packages.json"
BUILD_ZIG_ZON_JSON="$ROOT/build.zig.zon.json"
if [ ! -f "${BUILD_ZIG_ZON_JSON}" ]; then
echo -e "\nERROR: build.zig.zon2json-lock missing."
help
exit 1
fi
if [ -f "${ZIG_PACKAGES_JSON}" ]; then
OLD_HASH=$(sha512sum "${ZIG_PACKAGES_JSON}" | awk '{print $1}')
fi
while read -r url sha256 dest; do
src_type=archive
sha256=$(decode_hash "$sha256")
git_commit=
if [[ "$url" =~ ^git\+* ]]; then
src_type=git
sha256=
url=${url#git+}
git_commit=${url##*#}
url=${url%%/\?ref*}
url=${url%%#*}
fi
jq \
-nec \
--arg type "$src_type" \
--arg url "$url" \
--arg git_commit "$git_commit" \
--arg dest "$dest" \
--arg sha256 "$sha256" \
'{
type: $type,
url: $url,
commit: $git_commit,
dest: $dest,
sha256: $sha256,
} | with_entries(select(.value != ""))'
done < <(jq -rc 'to_entries[] | [.value.url, .value.hash, "vendor/p/\(.key)"] | @tsv' "$BUILD_ZIG_ZON_JSON") |
jq -s '.' >"$WORK_DIR/zig-packages.json"
NEW_HASH=$(sha512sum "$WORK_DIR/zig-packages.json" | awk '{print $1}')
if [ "${OLD_HASH}" == "${NEW_HASH}" ]; then
echo -e "\nOK: flatpak/zig-packages.json unchanged."
exit 0
elif [ "${1:-}" != "--update" ]; then
echo -e "\nERROR: flatpak/zig-packages.json needs to be updated."
echo ""
echo " * Old hash: ${OLD_HASH}"
echo " * New hash: ${NEW_HASH}"
help
exit 1
else
mv "$WORK_DIR/zig-packages.json" "$ZIG_PACKAGES_JSON"
echo -e "\nOK: flatpak/zig-packages.json updated."
exit 0
fi

View File

@@ -2,8 +2,6 @@ app-id: com.mitchellh.ghostty-debug
runtime: org.gnome.Platform
runtime-version: "48"
sdk: org.gnome.Sdk
sdk-extensions:
- org.freedesktop.Sdk.Extension.ziglang
default-branch: tip
command: ghostty
rename-icon: com.mitchellh.ghostty
@@ -37,7 +35,7 @@ modules:
- name: ghostty
buildsystem: simple
build-options:
append-path: /usr/lib/sdk/ziglang
append-path: /app/zig
build-commands:
- zig build
-Doptimize=Debug

View File

@@ -2,8 +2,6 @@ app-id: com.mitchellh.ghostty
runtime: org.gnome.Platform
runtime-version: "48"
sdk: org.gnome.Sdk
sdk-extensions:
- org.freedesktop.Sdk.Extension.ziglang
default-branch: tip
command: ghostty
finish-args:
@@ -36,7 +34,7 @@ modules:
- name: ghostty
buildsystem: simple
build-options:
append-path: /usr/lib/sdk/ziglang
append-path: /app/zig
build-commands:
- zig build
-Doptimize=ReleaseFast

View File

@@ -3,6 +3,24 @@ buildsystem: simple
build-commands:
- true
modules:
- name: zig
buildsystem: simple
cleanup:
- "*"
build-commands:
- mkdir -p /app/zig
- cp -r ./* /app/zig
- 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
only-arches: [x86_64]
- type: archive
sha256: f7a654acc967864f7a050ddacfaa778c7504a0eca8d2b678839c21eea47c992b
url: https://ziglang.org/download/0.14.1/zig-aarch64-linux-0.14.1.tar.xz
only-arches: [aarch64]
- name: bzip2-redirect
buildsystem: simple
build-commands:

View File

@@ -31,9 +31,9 @@
},
{
"type": "archive",
"url": "https://github.com/jcollie/ghostty-gobject/releases/download/0.14.1-2025-07-19-27-1/ghostty-gobject-0.14.1-2025-07-19-27-1.tar.zst",
"dest": "vendor/p/gobject-0.3.0-Skun7KzYnAAsvbz0JzKA4LBdXbLqj0eNXHoKAIE0HkOl",
"sha256": "738b333c50be2f61fc650de0edaa158be94f985e08e924f137df9f061c5a6a9f"
"url": "https://github.com/jcollie/ghostty-gobject/releases/download/0.14.1-2025-08-09-37-1/ghostty-gobject-0.14.1-2025-08-09-37-1.tar.zst",
"dest": "vendor/p/gobject-0.3.0-Skun7AngnABC2BPiaoobs6YSSzSgMuEIcjb2rYrRyaAM",
"sha256": "074ce22f32ae77e91d2aee53d414c4f46321f043ccfca861868349972b3940f2"
},
{
"type": "archive",
@@ -61,9 +61,9 @@
},
{
"type": "archive",
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/92f20650771384b82f981fb0f249e5fbdcb69e9f.tar.gz",
"dest": "vendor/p/N-V-__8AAGHcWgSXHA9Fw-E0Hbe5EZWyYyI1AvW9O_HBbkRH",
"sha256": "b10e4858a41d114dcc387cf1a2f8c0e033ba7ffaf2bed5b5f1a213378064a20d"
"url": "https://github.com/mbadolato/iTerm2-Color-Schemes/archive/6cdbc8501d48601302e32d6b53e9e7934bf354b4.tar.gz",
"dest": "vendor/p/N-V-__8AAAtjXwSdhZq_xYbCXo0SZMqoNoQuHFkC07sijQME",
"sha256": "3655177013a6680f16fbb457b97727f532219bdeb87573b63a9e10090c610f27"
},
{
"type": "archive",
@@ -157,9 +157,9 @@
},
{
"type": "archive",
"url": "https://github.com/vancluever/z2d/archive/8bbd035f4101f02b1d27947def0d7da3215df7fe.tar.gz",
"dest": "vendor/p/z2d-0.7.0-j5P_Hg_DDACq-2H2Zh7rAq6_TXWdQzv7JAUfnrdeDosg",
"sha256": "c1f69d7a07a2c5c6e0c51cd1b5fe8cd87df8093baf0ccdb65d5221bae7c5046e"
"url": "https://github.com/vancluever/z2d/archive/refs/tags/v0.7.2.tar.gz",
"dest": "vendor/p/z2d-0.7.2-j5P_Hm1oDQDQsWpGfSCMARhowBnuTHlQ_sBfij6TuG7l",
"sha256": "b56acb944394e3fd193a5ce018e5c1d3c7d6eeca9fc8015fdeb96fd3097d6ff7"
},
{
"type": "archive",

BIN
images/gnome/1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

BIN
images/gnome/128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
images/gnome/16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 B

BIN
images/gnome/2048.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 KiB

BIN
images/gnome/256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
images/gnome/32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
images/gnome/512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
images/gnome/64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
images/gnome/nightly-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
images/gnome/nightly-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

BIN
images/gnome/nightly-64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -419,6 +419,7 @@ typedef struct {
ghostty_env_var_s* env_vars;
size_t env_var_count;
const char* initial_input;
bool wait_after_command;
} ghostty_surface_config_s;
typedef struct {
@@ -450,6 +451,28 @@ typedef struct {
ghostty_config_color_s colors[256];
} ghostty_config_palette_s;
// config.QuickTerminalSize
typedef enum {
GHOSTTY_QUICK_TERMINAL_SIZE_NONE,
GHOSTTY_QUICK_TERMINAL_SIZE_PERCENTAGE,
GHOSTTY_QUICK_TERMINAL_SIZE_PIXELS,
} ghostty_quick_terminal_size_tag_e;
typedef union {
float percentage;
uint32_t pixels;
} ghostty_quick_terminal_size_value_u;
typedef struct {
ghostty_quick_terminal_size_tag_e tag;
ghostty_quick_terminal_size_value_u value;
} ghostty_quick_terminal_size_s;
typedef struct {
ghostty_quick_terminal_size_s primary;
ghostty_quick_terminal_size_s secondary;
} ghostty_config_quick_terminal_size_s;
// apprt.Target.Key
typedef enum {
GHOSTTY_TARGET_APP,
@@ -680,6 +703,12 @@ typedef struct {
uintptr_t len;
} ghostty_action_open_url_s;
// apprt.action.CloseTabMode
typedef enum {
GHOSTTY_ACTION_CLOSE_TAB_MODE_THIS,
GHOSTTY_ACTION_CLOSE_TAB_MODE_OTHER,
} ghostty_action_close_tab_mode_e;
// apprt.surface.Message.ChildExited
typedef struct {
uint32_t exit_code;
@@ -693,15 +722,15 @@ typedef enum {
GHOSTTY_PROGRESS_STATE_ERROR,
GHOSTTY_PROGRESS_STATE_INDETERMINATE,
GHOSTTY_PROGRESS_STATE_PAUSE,
} ghostty_terminal_osc_command_progressreport_state_e;
} ghostty_action_progress_report_state_e;
// terminal.osc.Command.ProgressReport.C
typedef struct {
ghostty_terminal_osc_command_progressreport_state_e state;
ghostty_action_progress_report_state_e state;
// -1 if no progress was reported, otherwise 0-100 indicating percent
// completeness.
int8_t progress;
} ghostty_terminal_osc_command_progressreport_s;
} ghostty_action_progress_report_s;
// apprt.Action.Key
typedef enum {
@@ -757,6 +786,7 @@ typedef enum {
GHOSTTY_ACTION_OPEN_URL,
GHOSTTY_ACTION_SHOW_CHILD_EXITED,
GHOSTTY_ACTION_PROGRESS_REPORT,
GHOSTTY_ACTION_SHOW_ON_SCREEN_KEYBOARD,
} ghostty_action_tag_e;
typedef union {
@@ -785,8 +815,9 @@ typedef union {
ghostty_action_reload_config_s reload_config;
ghostty_action_config_change_s config_change;
ghostty_action_open_url_s open_url;
ghostty_action_close_tab_mode_e close_tab_mode;
ghostty_surface_message_childexited_s child_exited;
ghostty_terminal_osc_command_progressreport_s progress_report;
ghostty_action_progress_report_s progress_report;
} ghostty_action_u;
typedef struct {
@@ -933,7 +964,7 @@ void ghostty_surface_mouse_scroll(ghostty_surface_t,
double,
ghostty_input_scroll_mods_t);
void ghostty_surface_mouse_pressure(ghostty_surface_t, uint32_t, double);
void ghostty_surface_ime_point(ghostty_surface_t, double*, double*);
void ghostty_surface_ime_point(ghostty_surface_t, double*, double*, double*, double*);
void ghostty_surface_request_close(ghostty_surface_t);
void ghostty_surface_split(ghostty_surface_t, ghostty_action_split_direction_e);
void ghostty_surface_split_focus(ghostty_surface_t,

View File

@@ -104,6 +104,7 @@
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 */; };
@@ -126,6 +127,7 @@
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 */; };
@@ -252,6 +254,7 @@
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>"; };
@@ -637,6 +640,7 @@
CFBB5FE92D231E5000FD62EE /* QuickTerminalSpaceBehavior.swift */,
A5CBD0632CA122E70017A1AE /* QuickTerminalPosition.swift */,
A52FFF562CA90481000C6A5B /* QuickTerminalScreen.swift */,
A5BB78B82DF9D8CE009AC3FA /* QuickTerminalSize.swift */,
A5CBD05F2CA0C9080017A1AE /* QuickTerminalWindow.swift */,
);
path = QuickTerminal;
@@ -939,6 +943,10 @@
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 */,
@@ -980,6 +988,7 @@
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 */,

View File

@@ -6,8 +6,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/sparkle-project/Sparkle",
"state" : {
"revision" : "0ef1ee0220239b3776f433314515fd849025673f",
"version" : "2.6.4"
"revision" : "df074165274afaa39539c05d57b0832620775b11",
"version" : "2.7.1"
}
}
],

View File

@@ -119,6 +119,9 @@ class AppDelegate: NSObject,
@Published private(set) var appIcon: NSImage? = nil {
didSet {
NSApplication.shared.applicationIconImage = appIcon
let appPath = Bundle.main.bundlePath
NSWorkspace.shared.setIcon(appIcon, forFile: appPath, options: [])
NSWorkspace.shared.noteFileSystemChanged(appPath)
}
}
@@ -255,13 +258,13 @@ class AppDelegate: NSObject,
// Setup signal handlers
setupSignals()
// If we launched via zig run then we need to force foreground.
if Ghostty.launchSource == .zig_run {
// This never gets called until we click the dock icon. This forces it
// activate immediately.
applicationDidBecomeActive(.init(name: NSApplication.didBecomeActiveNotification))
// We run in the background, this forces us to the front.
DispatchQueue.main.async {
NSApp.setActivationPolicy(.regular)
@@ -391,34 +394,69 @@ class AppDelegate: NSObject,
// Ghostty will validate as well but we can avoid creating an entirely new
// surface by doing our own validation here. We can also show a useful error
// this way.
var isDirectory = ObjCBool(true)
guard FileManager.default.fileExists(atPath: filename, isDirectory: &isDirectory) else { return false }
// Set to true if confirmation is required before starting up the
// new terminal.
var requiresConfirm: Bool = false
// Initialize the surface config which will be used to create the tab or window for the opened file.
var config = Ghostty.SurfaceConfiguration()
if (isDirectory.boolValue) {
// When opening a directory, create a new tab in the main
// window with that as the working directory.
// If no windows exist, a new one will be created.
// When opening a directory, check the configuration to decide
// whether to open in a new tab or new window.
config.workingDirectory = filename
_ = TerminalController.newTab(ghostty, withBaseConfig: config)
} else {
// Unconditionally require confirmation in the file execution case.
// In the future I have ideas about making this more fine-grained if
// we can not inherit of unsandboxed state. For now, we need to confirm
// because there is a sandbox escape possible if a sandboxed application
// somehow is tricked into `open`-ing a non-sandboxed application.
requiresConfirm = true
// When opening a file, we want to execute the file. To do this, we
// don't override the command directly, because it won't load the
// profile/rc files for the shell, which is super important on macOS
// due to things like Homebrew. Instead, we set the command to
// `<filename>; exit` which is what Terminal and iTerm2 do.
config.initialInput = "\(filename); exit\n"
// For commands executed directly, we want to ensure we wait after exit
// because in most cases scripts don't block on exit and we don't want
// the window to just flash closed once complete.
config.waitAfterCommand = true
// Set the parent directory to our working directory so that relative
// paths in scripts work.
config.workingDirectory = (filename as NSString).deletingLastPathComponent
_ = TerminalController.newWindow(ghostty, withBaseConfig: config)
}
if requiresConfirm {
// Confirmation required. We use an app-wide NSAlert for now. In the future we
// may want to show this as a sheet on the focused window (especially if we're
// opening a tab). I'm not sure.
let alert = NSAlert()
alert.messageText = "Allow Ghostty to execute \"\(filename)\"?"
alert.addButton(withTitle: "Allow")
alert.addButton(withTitle: "Cancel")
alert.alertStyle = .warning
switch (alert.runModal()) {
case .alertFirstButtonReturn:
break
default:
return false
}
}
switch ghostty.config.macosDockDropBehavior {
case .new_tab: _ = TerminalController.newTab(ghostty, withBaseConfig: config)
case .new_window: _ = TerminalController.newWindow(ghostty, withBaseConfig: config)
}
return true
}
@@ -471,6 +509,7 @@ class AppDelegate: NSObject,
self.menuSplitUp?.setImageIfDesired(systemSymbolName: "rectangle.tophalf.inset.filled")
self.menuSplitDown?.setImageIfDesired(systemSymbolName: "rectangle.bottomhalf.inset.filled")
self.menuClose?.setImageIfDesired(systemSymbolName: "xmark")
self.menuPasteSelection?.setImageIfDesired(systemSymbolName: "doc.on.clipboard.fill")
self.menuIncreaseFontSize?.setImageIfDesired(systemSymbolName: "textformat.size.larger")
self.menuResetFontSize?.setImageIfDesired(systemSymbolName: "textformat.size")
self.menuDecreaseFontSize?.setImageIfDesired(systemSymbolName: "textformat.size.smaller")
@@ -492,7 +531,7 @@ class AppDelegate: NSObject,
self.menuMoveSplitDividerDown?.setImageIfDesired(systemSymbolName: "arrow.down.to.line")
self.menuMoveSplitDividerLeft?.setImageIfDesired(systemSymbolName: "arrow.left.to.line")
self.menuMoveSplitDividerRight?.setImageIfDesired(systemSymbolName: "arrow.right.to.line")
self.menuFloatOnTop?.setImageIfDesired(systemSymbolName: "square.3.layers.3d.top.filled")
self.menuFloatOnTop?.setImageIfDesired(systemSymbolName: "square.filled.on.square")
}
/// Sync all of our menu item keyboard shortcuts with the Ghostty configuration.
@@ -833,6 +872,13 @@ class AppDelegate: NSObject,
case .xray:
self.appIcon = NSImage(named: "XrayImage")!
case .custom:
if let userIcon = NSImage(contentsOfFile: config.macosCustomIcon) {
self.appIcon = userIcon
} else {
self.appIcon = nil // Revert back to official icon if invalid location
}
case .customStyle:
guard let ghostColor = config.macosIconGhostColor else { break }
guard let screenColors = config.macosIconScreenColor else { break }
@@ -945,18 +991,10 @@ class AppDelegate: NSObject,
@IBAction func newWindow(_ sender: Any?) {
_ = TerminalController.newWindow(ghostty)
// We also activate our app so that it becomes front. This may be
// necessary for the dock menu.
NSApp.activate(ignoringOtherApps: true)
}
@IBAction func newTab(_ sender: Any?) {
_ = TerminalController.newTab(ghostty)
// We also activate our app so that it becomes front. This may be
// necessary for the dock menu.
NSApp.activate(ignoringOtherApps: true)
}
@IBAction func closeAllWindows(_ sender: Any?) {

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="24093.7" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="24123.1" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24093.7"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24123.1"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">

View File

@@ -14,7 +14,7 @@ struct TerminalEntity: AppEntity {
@Property(title: "Kind")
var kind: Kind
var screenshot: Image?
var screenshot: NSImage?
static var typeDisplayRepresentation: TypeDisplayRepresentation {
TypeDisplayRepresentation(name: "Terminal")
@@ -24,8 +24,7 @@ struct TerminalEntity: AppEntity {
var displayRepresentation: DisplayRepresentation {
var rep = DisplayRepresentation(title: "\(title)")
if let screenshot,
let nsImage = ImageRenderer(content: screenshot).nsImage,
let data = nsImage.tiffRepresentation {
let data = screenshot.tiffRepresentation {
rep.image = .init(data: data)
}
@@ -45,11 +44,14 @@ struct TerminalEntity: AppEntity {
static var defaultQuery = TerminalQuery()
@MainActor
init(_ view: Ghostty.SurfaceView) {
self.id = view.uuid
self.title = view.title
self.workingDirectory = view.pwd
self.screenshot = view.screenshot()
if let nsImage = ImageRenderer(content: view.screenshot()).nsImage {
self.screenshot = nsImage
}
// Determine the kind based on the window controller type
if view.window?.windowController is QuickTerminalController {

View File

@@ -22,7 +22,7 @@ class QuickTerminalController: BaseTerminalController {
private var previousActiveSpace: CGSSpace? = nil
/// The window frame saved 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
@@ -34,6 +34,9 @@ class QuickTerminalController: BaseTerminalController {
/// The configuration derived from the Ghostty config so we don't need to rely on references.
private var derivedConfig: DerivedConfig
/// Tracks if we're currently handling a manual resize to prevent recursion
private var isHandlingResize: Bool = false
init(_ ghostty: Ghostty.App,
position: QuickTerminalPosition = .top,
@@ -76,6 +79,11 @@ class QuickTerminalController: BaseTerminalController {
selector: #selector(onNewTab),
name: Ghostty.Notification.ghosttyNewTab,
object: nil)
center.addObserver(
self,
selector: #selector(windowDidResize(_:)),
name: NSWindow.didResizeNotification,
object: nil)
}
required init?(coder: NSCoder) {
@@ -109,14 +117,29 @@ class QuickTerminalController: BaseTerminalController {
syncAppearance()
// Setup our initial size based on our configured position
position.setLoaded(window)
position.setLoaded(window, size: derivedConfig.quickTerminalSize)
// Upon first adding this Window to its host view, older SwiftUI
// seems to have a "hiccup" and corrupts the frameRect,
// sometimes setting the size to zero, sometimes corrupting it.
// We pass the actual window's frame as "initial" frame directly
// to the window, so it can use that instead of the frameworks
// "interpretation"
if let qtWindow = window as? QuickTerminalWindow {
qtWindow.initialFrame = window.frame
}
// Setup our content
window.contentView = NSHostingView(rootView: TerminalView(
ghostty: self.ghostty,
viewModel: self,
delegate: self
))
// Clear out our frame at this point, the fixup from above is complete.
if let qtWindow = window as? QuickTerminalWindow {
qtWindow.initialFrame = nil
}
// Animate the window in
animateIn()
@@ -194,11 +217,28 @@ class QuickTerminalController: BaseTerminalController {
}
}
func windowWillResize(_ sender: NSWindow, to frameSize: NSSize) -> NSSize {
// We use the actual screen the window is on for this, since it should
// be on the proper screen.
guard let screen = window?.screen ?? NSScreen.main else { return frameSize }
return position.restrictFrameSize(frameSize, on: screen)
override func windowDidResize(_ notification: Notification) {
guard let window = notification.object as? NSWindow,
window == self.window,
visible,
!isHandlingResize else { return }
guard let screen = window.screen ?? NSScreen.main else { return }
// Prevent recursive loops
isHandlingResize = true
defer { isHandlingResize = false }
switch position {
case .top, .bottom, .center:
// For centered positions (top, bottom, center), we need to recenter the window
// when it's manually resized to maintain proper positioning
let newOrigin = position.centeredOrigin(for: window, on: screen)
window.setFrameOrigin(newOrigin)
case .left, .right:
// For side positions, we may need to adjust vertical centering
let newOrigin = position.verticallyCenteredOrigin(for: window, on: screen)
window.setFrameOrigin(newOrigin)
}
}
// MARK: Base Controller Overrides
@@ -318,15 +358,17 @@ class QuickTerminalController: BaseTerminalController {
private func animateWindowIn(window: NSWindow, from position: QuickTerminalPosition) {
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
// Restore our previous frame if we have one
if let lastClosedFrame {
window.setFrame(lastClosedFrame, display: false)
self.lastClosedFrame = nil
}
// Move our window off screen to the top
position.setInitial(in: window, on: screen)
// Move our window off screen to the initial animation position.
position.setInitial(
in: window,
on: screen,
terminalSize: derivedConfig.quickTerminalSize,
closedFrame: lastClosedFrame)
// We need to set our window level to a high value. In testing, only
// popUpMenu and above do what we want. This gets it above the menu bar
@@ -357,7 +399,11 @@ class QuickTerminalController: BaseTerminalController {
NSAnimationContext.runAnimationGroup({ context in
context.duration = derivedConfig.quickTerminalAnimationDuration
context.timingFunction = .init(name: .easeIn)
position.setFinal(in: window.animator(), on: screen)
position.setFinal(
in: window.animator(),
on: screen,
terminalSize: derivedConfig.quickTerminalSize,
closedFrame: lastClosedFrame)
}, completionHandler: {
// There is a very minor delay here so waiting at least an event loop tick
// keeps us safe from the view not being on the window.
@@ -435,11 +481,19 @@ class QuickTerminalController: BaseTerminalController {
}
private func animateWindowOut(window: NSWindow, to position: QuickTerminalPosition) {
// If we are in fullscreen, then we exit fullscreen. We do this immediately so
// we have th correct window.frame for the save state below.
if let fullscreenStyle, fullscreenStyle.isFullscreen {
fullscreenStyle.exit()
}
// Save the current window frame before animating out. This preserves
// 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.
lastClosedFrame = window.frame
if window.frame.width > 0 && window.frame.height > 0 {
lastClosedFrame = window.frame
}
// If we hid the dock then we unhide it.
hiddenDock = nil
@@ -455,11 +509,6 @@ class QuickTerminalController: BaseTerminalController {
// We always animate out to whatever screen the window is actually on.
guard let screen = window.screen ?? NSScreen.main else { return }
// If we are in fullscreen, then we exit fullscreen.
if let fullscreenStyle, fullscreenStyle.isFullscreen {
fullscreenStyle.exit()
}
// If we have a previously active application, restore focus to it. We
// do this BEFORE the animation below because when the animation completes
// macOS will bring forward another window.
@@ -481,7 +530,11 @@ class QuickTerminalController: BaseTerminalController {
NSAnimationContext.runAnimationGroup({ context in
context.duration = derivedConfig.quickTerminalAnimationDuration
context.timingFunction = .init(name: .easeIn)
position.setInitial(in: window.animator(), on: screen)
position.setInitial(
in: window.animator(),
on: screen,
terminalSize: derivedConfig.quickTerminalSize,
closedFrame: window.frame)
}, completionHandler: {
// This causes the window to be removed from the screen list and macOS
// handles what should be focused next.
@@ -612,6 +665,7 @@ class QuickTerminalController: BaseTerminalController {
let quickTerminalAnimationDuration: Double
let quickTerminalAutoHide: Bool
let quickTerminalSpaceBehavior: QuickTerminalSpaceBehavior
let quickTerminalSize: QuickTerminalSize
let backgroundOpacity: Double
init() {
@@ -619,6 +673,7 @@ class QuickTerminalController: BaseTerminalController {
self.quickTerminalAnimationDuration = 0.2
self.quickTerminalAutoHide = true
self.quickTerminalSpaceBehavior = .move
self.quickTerminalSize = QuickTerminalSize()
self.backgroundOpacity = 1.0
}
@@ -627,6 +682,7 @@ class QuickTerminalController: BaseTerminalController {
self.quickTerminalAnimationDuration = config.quickTerminalAnimationDuration
self.quickTerminalAutoHide = config.quickTerminalAutoHide
self.quickTerminalSpaceBehavior = config.quickTerminalSpaceBehavior
self.quickTerminalSize = config.quickTerminalSize
self.backgroundOpacity = config.backgroundOpacity
}
}

View File

@@ -7,95 +7,86 @@ enum QuickTerminalPosition : String {
case right
case center
/// Set the loaded state for a window.
func setLoaded(_ window: NSWindow) {
/// Set the loaded state for a window. This should only be called when the window is first loaded,
/// usually in `windowDidLoad` or in a similar callback. This is the initial state.
func setLoaded(_ window: NSWindow, size: QuickTerminalSize) {
guard let screen = window.screen ?? NSScreen.main else { return }
switch (self) {
case .top, .bottom:
window.setFrame(.init(
origin: window.frame.origin,
size: .init(
width: screen.frame.width,
height: screen.frame.height / 4)
), display: false)
case .left, .right:
window.setFrame(.init(
origin: window.frame.origin,
size: .init(
width: screen.frame.width / 4,
height: screen.frame.height)
), display: false)
case .center:
window.setFrame(.init(
origin: window.frame.origin,
size: .init(
width: screen.frame.width / 2,
height: screen.frame.height / 3)
), display: false)
}
window.setFrame(.init(
origin: window.frame.origin,
size: size.calculate(position: self, screenDimensions: screen.visibleFrame.size)
), display: false)
}
/// Set the initial state for a window for animating out of this position.
func setInitial(in window: NSWindow, on screen: NSScreen) {
// We always start invisible
/// Set the initial state for a window NOT yet into position (either before animating in or
/// after animating out).
func setInitial(
in window: NSWindow,
on screen: NSScreen,
terminalSize: QuickTerminalSize,
closedFrame: NSRect? = nil
) {
// Invisible
window.alphaValue = 0
// Position depends
window.setFrame(.init(
origin: initialOrigin(for: window, on: screen),
size: restrictFrameSize(window.frame.size, on: screen)
size: closedFrame?.size ?? configuredFrameSize(
on: screen,
terminalSize: terminalSize)
), display: false)
}
/// Set the final state for a window in this position.
func setFinal(in window: NSWindow, on screen: NSScreen) {
func setFinal(
in window: NSWindow,
on screen: NSScreen,
terminalSize: QuickTerminalSize,
closedFrame: NSRect? = nil
) {
// We always end visible
window.alphaValue = 1
// Position depends
window.setFrame(.init(
origin: finalOrigin(for: window, on: screen),
size: restrictFrameSize(window.frame.size, on: screen)
size: closedFrame?.size ?? configuredFrameSize(
on: screen,
terminalSize: terminalSize)
), display: true)
}
/// Restrict the frame size during resizing.
func restrictFrameSize(_ size: NSSize, on screen: NSScreen) -> NSSize {
var finalSize = size
switch (self) {
case .top, .bottom:
finalSize.width = screen.frame.width
case .left, .right:
finalSize.height = screen.visibleFrame.height
case .center:
finalSize.width = screen.frame.width / 2
finalSize.height = screen.frame.height / 3
}
return finalSize
/// Get the configured frame size for initial positioning and animations.
func configuredFrameSize(on screen: NSScreen, terminalSize: QuickTerminalSize) -> NSSize {
let dimensions = terminalSize.calculate(position: self, screenDimensions: screen.visibleFrame.size)
return NSSize(width: dimensions.width, height: dimensions.height)
}
/// The initial point origin for this position.
func initialOrigin(for window: NSWindow, on screen: NSScreen) -> CGPoint {
switch (self) {
case .top:
return .init(x: screen.frame.minX, y: screen.frame.maxY)
return .init(
x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2),
y: screen.visibleFrame.maxY)
case .bottom:
return .init(x: screen.frame.minX, y: -window.frame.height)
return .init(
x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2),
y: -window.frame.height)
case .left:
return .init(x: screen.frame.minX-window.frame.width, y: 0)
return .init(
x: screen.visibleFrame.minX-window.frame.width,
y: round(screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2))
case .right:
return .init(x: screen.frame.maxX, y: 0)
return .init(
x: screen.visibleFrame.maxX,
y: round(screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2))
case .center:
return .init(x: screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2, y: screen.visibleFrame.height - window.frame.width)
return .init(x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2), y: screen.visibleFrame.height - window.frame.width)
}
}
@@ -103,19 +94,27 @@ enum QuickTerminalPosition : String {
func finalOrigin(for window: NSWindow, on screen: NSScreen) -> CGPoint {
switch (self) {
case .top:
return .init(x: screen.frame.minX, y: screen.visibleFrame.maxY - window.frame.height)
return .init(
x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2),
y: screen.visibleFrame.maxY - window.frame.height)
case .bottom:
return .init(x: screen.frame.minX, y: screen.frame.minY)
return .init(
x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2),
y: screen.visibleFrame.minY)
case .left:
return .init(x: screen.frame.minX, y: window.frame.origin.y)
return .init(
x: screen.visibleFrame.minX,
y: round(screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2))
case .right:
return .init(x: screen.visibleFrame.maxX - window.frame.width, y: window.frame.origin.y)
return .init(
x: screen.visibleFrame.maxX - window.frame.width,
y: round(screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2))
case .center:
return .init(x: screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2, y: screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2)
return .init(x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2), y: round(screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2))
}
}
@@ -136,4 +135,52 @@ enum QuickTerminalPosition : String {
case .right: self == .top || self == .bottom
}
}
/// Calculate the centered origin for a window, keeping it properly positioned after manual resizing
func centeredOrigin(for window: NSWindow, on screen: NSScreen) -> CGPoint {
switch self {
case .top:
return CGPoint(
x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2),
y: window.frame.origin.y // Keep the same Y position
)
case .bottom:
return CGPoint(
x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2),
y: window.frame.origin.y // Keep the same Y position
)
case .center:
return CGPoint(
x: round(screen.visibleFrame.origin.x + (screen.visibleFrame.width - window.frame.width) / 2),
y: round(screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2)
)
case .left, .right:
// For left/right positions, only adjust horizontal centering if needed
return window.frame.origin
}
}
/// Calculate the vertically centered origin for side-positioned windows
func verticallyCenteredOrigin(for window: NSWindow, on screen: NSScreen) -> CGPoint {
switch self {
case .left:
return CGPoint(
x: window.frame.origin.x, // Keep the same X position
y: round(screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2)
)
case .right:
return CGPoint(
x: window.frame.origin.x, // Keep the same X position
y: round(screen.visibleFrame.origin.y + (screen.visibleFrame.height - window.frame.height) / 2)
)
case .top, .bottom, .center:
// These positions don't need vertical recentering during resize
return window.frame.origin
}
}
}

View File

@@ -0,0 +1,84 @@
import GhosttyKit
/// Represents the Ghostty `quick-terminal-size` configuration. See the documentation for
/// that for more details on exactly how it works. Some of those docs will be reproduced in various comments
/// in this file but that is the best source of truth for it.
///
/// The size determines the size of the quick terminal along the primary and secondary axis. The primary and
/// secondary axis is defined by the `quick-terminal-position`.
struct QuickTerminalSize {
let primary: Size?
let secondary: Size?
init(primary: Size? = nil, secondary: Size? = nil) {
self.primary = primary
self.secondary = secondary
}
init(from cStruct: ghostty_config_quick_terminal_size_s) {
self.primary = Size(from: cStruct.primary)
self.secondary = Size(from: cStruct.secondary)
}
enum Size {
case percentage(Float)
case pixels(UInt32)
init?(from cStruct: ghostty_quick_terminal_size_s) {
switch cStruct.tag {
case GHOSTTY_QUICK_TERMINAL_SIZE_NONE:
return nil
case GHOSTTY_QUICK_TERMINAL_SIZE_PERCENTAGE:
self = .percentage(cStruct.value.percentage)
case GHOSTTY_QUICK_TERMINAL_SIZE_PIXELS:
self = .pixels(cStruct.value.pixels)
default:
return nil
}
}
func toPixels(parentDimension: CGFloat) -> CGFloat {
switch self {
case .percentage(let value):
return parentDimension * CGFloat(value) / 100.0
case .pixels(let value):
return CGFloat(value)
}
}
}
/// This is an almost direct port of th Zig function QuickTerminalSize.calculate
func calculate(position: QuickTerminalPosition, screenDimensions: CGSize) -> CGSize {
let dims = CGSize(width: screenDimensions.width, height: screenDimensions.height)
switch position {
case .left, .right:
return CGSize(
width: primary?.toPixels(parentDimension: dims.width) ?? 400,
height: secondary?.toPixels(parentDimension: dims.height) ?? dims.height
)
case .top, .bottom:
return CGSize(
width: secondary?.toPixels(parentDimension: dims.width) ?? dims.width,
height: primary?.toPixels(parentDimension: dims.height) ?? 400
)
case .center:
if dims.width >= dims.height {
// Landscape
return CGSize(
width: primary?.toPixels(parentDimension: dims.width) ?? 800,
height: secondary?.toPixels(parentDimension: dims.height) ?? 400
)
} else {
// Portrait
return CGSize(
width: secondary?.toPixels(parentDimension: dims.width) ?? 400,
height: primary?.toPixels(parentDimension: dims.height) ?? 800
)
}
}
}
}

View File

@@ -29,4 +29,19 @@ class QuickTerminalWindow: NSPanel {
// We don't want to activate the owning app when quick terminal is triggered.
self.styleMask.insert(.nonactivatingPanel)
}
/// This is set to the frame prior to setting `contentView`. This is purely a hack to workaround
/// bugs in older macOS versions (Ventura): https://github.com/ghostty-org/ghostty/pull/8026
var initialFrame: NSRect? = nil
override func setFrame(_ frameRect: NSRect, display flag: Bool) {
// Upon first adding this Window to its host view, older SwiftUI
// seems to have a "hiccup" and corrupts the frameRect,
// sometimes setting the size to zero, sometimes corrupting it.
// If we find we have cached the "initial" frame, use that instead
// the propagated one through the framework
//
// https://github.com/ghostty-org/ghostty/pull/8026
super.setFrame(initialFrame ?? frameRect, display: flag)
}
}

View File

@@ -290,8 +290,12 @@ class BaseTerminalController: NSWindowController,
alert.addButton(withTitle: "Cancel")
alert.alertStyle = .warning
alert.beginSheetModal(for: window) { response in
let alertWindow = alert.window
self.alert = nil
if response == .alertFirstButtonReturn {
// This is important so that we avoid losing focus when Stage
// Manager is used (#8336)
alertWindow.orderOut(nil)
completion()
}
}

View File

@@ -95,6 +95,11 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
selector: #selector(onCloseTab),
name: .ghosttyCloseTab,
object: nil)
center.addObserver(
self,
selector: #selector(onCloseOtherTabs),
name: .ghosttyCloseOtherTabs,
object: nil)
center.addObserver(
self,
selector: #selector(onResetWindowSize),
@@ -196,7 +201,12 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
if let parent {
if parent.styleMask.contains(.fullScreen) {
parent.toggleFullScreen(nil)
// If our previous window was fullscreen then we want our new window to
// be fullscreen. This behavior actually doesn't match the native tabbing
// behavior of macOS apps where new windows create tabs when in native
// fullscreen but this is how we've always done it. This matches iTerm2
// behavior.
c.toggleFullscreen(mode: .native)
} else if ghostty.config.windowFullscreen {
switch (ghostty.config.windowFullscreenMode) {
case .native:
@@ -226,6 +236,10 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
}
c.showWindow(self)
// All new_window actions force our app to be active, so that the new
// window is focused and visible.
NSApp.activate(ignoringOtherApps: true)
}
// Setup our undo
@@ -332,6 +346,10 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
controller.showWindow(self)
window.makeKeyAndOrderFront(self)
// We also activate our app so that it becomes front. This may be
// necessary for the dock menu.
NSApp.activate(ignoringOtherApps: true)
}
// It takes an event loop cycle until the macOS tabGroup state becomes
@@ -421,8 +439,7 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
continue
}
let action = "goto_tab:\(tab)"
if let equiv = ghostty.config.keyboardShortcut(for: action) {
if let equiv = ghostty.config.keyboardShortcut(for: "goto_tab:\(tab)") {
window.keyEquivalent = "\(equiv)"
} else {
window.keyEquivalent = ""
@@ -546,7 +563,7 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
closeWindow(nil)
}
private func closeTabImmediately() {
private func closeTabImmediately(registerRedo: Bool = true) {
guard let window = window else { return }
guard let tabGroup = window.tabGroup,
tabGroup.windows.count > 1 else {
@@ -563,19 +580,69 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
expiresAfter: undoExpiration
) { ghostty in
let newController = TerminalController(ghostty, with: undoState)
// Register redo action
undoManager.registerUndo(
withTarget: newController,
expiresAfter: newController.undoExpiration
) { target in
target.closeTabImmediately()
if registerRedo {
undoManager.registerUndo(
withTarget: newController,
expiresAfter: newController.undoExpiration
) { target in
target.closeTabImmediately()
}
}
}
}
window.close()
}
private func closeOtherTabsImmediately() {
guard let window = window else { return }
guard let tabGroup = window.tabGroup else { return }
guard tabGroup.windows.count > 1 else { return }
// Start an undo grouping
if let undoManager {
undoManager.beginUndoGrouping()
}
defer {
undoManager?.endUndoGrouping()
}
// Iterate through all tabs except the current one.
for window in tabGroup.windows where window != self.window {
// We ignore any non-terminal tabs. They don't currently exist and we can't
// properly undo them anyways so I'd rather ignore them and get a bug report
// later if and when we introduce non-terminal tabs.
if let controller = window.windowController as? TerminalController {
// We must not register a redo, because it messes with our own redo
// that we register later.
controller.closeTabImmediately(registerRedo: false)
}
}
if let undoManager {
undoManager.setActionName("Close Other Tabs")
// We need to register an undo that refocuses this window. Otherwise, the
// undo operation above for each tab will steal focus.
undoManager.registerUndo(
withTarget: self,
expiresAfter: undoExpiration
) { target in
DispatchQueue.main.async {
target.window?.makeKeyAndOrderFront(nil)
}
// Register redo action
undoManager.registerUndo(
withTarget: target,
expiresAfter: target.undoExpiration
) { target in
target.closeOtherTabsImmediately()
}
}
}
}
/// Closes the current window (including any other tabs) immediately and without
/// confirmation. This will setup proper undo state so the action can be undone.
@@ -739,6 +806,9 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
alert.alertStyle = .warning
alert.beginSheetModal(for: alertWindow, completionHandler: { response in
if (response == .alertFirstButtonReturn) {
// This is important so that we avoid losing focus when Stage
// Manager is used (#8336)
alert.window.orderOut(nil)
closeAllWindowsImmediately()
}
})
@@ -1007,6 +1077,38 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
}
}
@IBAction func closeOtherTabs(_ sender: Any?) {
guard let window = window else { return }
guard let tabGroup = window.tabGroup else { return }
// If we only have one window then we have no other tabs to close
guard tabGroup.windows.count > 1 else { return }
// Check if we have to confirm close.
guard tabGroup.windows.contains(where: { window in
// Ignore ourself
if window == self.window { return false }
// Ignore non-terminals
guard let controller = window.windowController as? TerminalController else {
return false
}
// Check if any surfaces require confirmation
return controller.surfaceTree.contains(where: { $0.needsConfirmQuit })
}) else {
self.closeOtherTabsImmediately()
return
}
confirmClose(
messageText: "Close Other Tabs?",
informativeText: "At least one other tab still has a running process. If you close the tab the process will be killed."
) {
self.closeOtherTabsImmediately()
}
}
@IBAction func returnToDefaultSize(_ sender: Any?) {
guard let defaultSize else { return }
window?.setFrame(defaultSize, display: true)
@@ -1190,6 +1292,12 @@ class TerminalController: BaseTerminalController, TabGroupCloseCoordinator.Contr
closeTab(self)
}
@objc private func onCloseOtherTabs(notification: SwiftUI.Notification) {
guard let target = notification.object as? Ghostty.SurfaceView else { return }
guard surfaceTree.contains(target) else { return }
closeOtherTabs(self)
}
@objc private func onCloseWindow(notification: SwiftUI.Notification) {
guard let target = notification.object as? Ghostty.SurfaceView else { return }
guard surfaceTree.contains(target) else { return }

View File

@@ -4,7 +4,7 @@ import Cocoa
class TerminalRestorableState: Codable {
static let selfKey = "state"
static let versionKey = "version"
static let version: Int = 3
static let version: Int = 4
let focusedSurface: String?
let surfaceTree: SplitTree<Ghostty.SurfaceView>

View File

@@ -70,4 +70,39 @@ extension Ghostty.Action {
}
}
}
struct ProgressReport {
enum State {
case remove
case set
case error
case indeterminate
case pause
init(_ c: ghostty_action_progress_report_state_e) {
switch c {
case GHOSTTY_PROGRESS_STATE_REMOVE:
self = .remove
case GHOSTTY_PROGRESS_STATE_SET:
self = .set
case GHOSTTY_PROGRESS_STATE_ERROR:
self = .error
case GHOSTTY_PROGRESS_STATE_INDETERMINATE:
self = .indeterminate
case GHOSTTY_PROGRESS_STATE_PAUSE:
self = .pause
default:
self = .remove
}
}
}
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
}
}
}

View File

@@ -455,7 +455,7 @@ extension Ghostty {
newSplit(app, target: target, direction: action.action.new_split)
case GHOSTTY_ACTION_CLOSE_TAB:
closeTab(app, target: target)
closeTab(app, target: target, mode: action.action.close_tab_mode)
case GHOSTTY_ACTION_CLOSE_WINDOW:
closeWindow(app, target: target)
@@ -543,6 +543,9 @@ extension Ghostty {
case GHOSTTY_ACTION_KEY_SEQUENCE:
keySequence(app, target: target, v: action.action.key_sequence)
case GHOSTTY_ACTION_PROGRESS_REPORT:
progressReport(app, target: target, v: action.action.progress_report)
case GHOSTTY_ACTION_CONFIG_CHANGE:
configChange(app, target: target, v: action.action.config_change)
@@ -778,20 +781,34 @@ extension Ghostty {
}
}
private static func closeTab(_ app: ghostty_app_t, target: ghostty_target_s) {
private static func closeTab(_ app: ghostty_app_t, target: ghostty_target_s, mode: ghostty_action_close_tab_mode_e) {
switch (target.tag) {
case GHOSTTY_TARGET_APP:
Ghostty.logger.warning("close tab does nothing with an app target")
Ghostty.logger.warning("close tabs does nothing with an app target")
return
case GHOSTTY_TARGET_SURFACE:
guard let surface = target.target.surface else { return }
guard let surfaceView = self.surfaceView(from: surface) else { return }
NotificationCenter.default.post(
name: .ghosttyCloseTab,
object: surfaceView
)
switch (mode) {
case GHOSTTY_ACTION_CLOSE_TAB_MODE_THIS:
NotificationCenter.default.post(
name: .ghosttyCloseTab,
object: surfaceView
)
return
case GHOSTTY_ACTION_CLOSE_TAB_MODE_OTHER:
NotificationCenter.default.post(
name: .ghosttyCloseOtherTabs,
object: surfaceView
)
return
default:
assertionFailure()
}
default:
@@ -1509,6 +1526,33 @@ extension Ghostty {
assertionFailure()
}
}
private static func progressReport(
_ app: ghostty_app_t,
target: ghostty_target_s,
v: ghostty_action_progress_report_s) {
switch (target.tag) {
case GHOSTTY_TARGET_APP:
Ghostty.logger.warning("progress report does nothing with an app target")
return
case GHOSTTY_TARGET_SURFACE:
guard let surface = target.target.surface else { return }
guard let surfaceView = self.surfaceView(from: surface) else { return }
let progressReport = Ghostty.Action.ProgressReport(c: v)
DispatchQueue.main.async {
if progressReport.state == .remove {
surfaceView.progressReport = nil
} else {
surfaceView.progressReport = progressReport
}
}
default:
assertionFailure()
}
}
private static func configReload(
_ app: ghostty_app_t,

View File

@@ -164,7 +164,7 @@ extension Ghostty {
let key = "window-position-x"
return ghostty_config_get(config, &v, key, UInt(key.count)) ? v : nil
}
var windowPositionY: Int16? {
guard let config = self.config else { return nil }
var v: Int16 = 0
@@ -282,6 +282,17 @@ extension Ghostty {
return MacOSTitlebarProxyIcon(rawValue: str) ?? defaultValue
}
var macosDockDropBehavior: MacDockDropBehavior {
let defaultValue = MacDockDropBehavior.new_tab
guard let config = self.config else { return defaultValue }
var v: UnsafePointer<Int8>? = nil
let key = "macos-dock-drop-behavior"
guard ghostty_config_get(config, &v, key, UInt(key.count)) else { return defaultValue }
guard let ptr = v else { return defaultValue }
let str = String(cString: ptr)
return MacDockDropBehavior(rawValue: str) ?? defaultValue
}
var macosWindowShadow: Bool {
guard let config = self.config else { return false }
var v = false;
@@ -301,6 +312,24 @@ extension Ghostty {
return MacOSIcon(rawValue: str) ?? defaultValue
}
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
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)
#else
return ""
#endif
}
var macosIconFrame: MacOSIconFrame {
let defaultValue = MacOSIconFrame.aluminum
guard let config = self.config else { return defaultValue }
@@ -475,6 +504,14 @@ extension Ghostty {
let str = String(cString: ptr)
return QuickTerminalSpaceBehavior(fromGhosttyConfig: str) ?? .move
}
var quickTerminalSize: QuickTerminalSize {
guard let config = self.config else { return QuickTerminalSize() }
var v = ghostty_config_quick_terminal_size_s()
let key = "quick-terminal-size"
guard ghostty_config_get(config, &v, key, UInt(key.count)) else { return QuickTerminalSize() }
return QuickTerminalSize(from: v)
}
#endif
var resizeOverlay: ResizeOverlay {
@@ -589,6 +626,11 @@ extension Ghostty.Config {
static let attention = BellFeatures(rawValue: 1 << 2)
static let title = BellFeatures(rawValue: 1 << 3)
}
enum MacDockDropBehavior: String {
case new_tab = "new-tab"
case new_window = "new-window"
}
enum MacHidden : String {
case never

View File

@@ -280,6 +280,7 @@ extension Ghostty {
case paper
case retro
case xray
case custom
case customStyle = "custom-style"
}
@@ -328,6 +329,9 @@ extension Notification.Name {
/// Close tab
static let ghosttyCloseTab = Notification.Name("com.mitchellh.ghostty.closeTab")
/// Close other tabs
static let ghosttyCloseOtherTabs = Notification.Name("com.mitchellh.ghostty.closeOtherTabs")
/// Close window
static let ghosttyCloseWindow = Notification.Name("com.mitchellh.ghostty.closeWindow")

View File

@@ -113,6 +113,11 @@ extension Ghostty {
}
}
.ghosttySurfaceView(surfaceView)
// Progress report overlay
if let progressReport = surfaceView.progressReport {
ProgressReportOverlay(report: progressReport)
}
#if canImport(AppKit)
// If we are in the middle of a key sequence, then we show a visual element. We only
@@ -267,6 +272,49 @@ 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.
struct SurfaceResizeOverlay: View {
@@ -424,6 +472,9 @@ extension Ghostty {
/// Extra input to send as stdin
var initialInput: String? = nil
/// Wait after the command
var waitAfterCommand: Bool = false
init() {}
@@ -475,6 +526,9 @@ extension Ghostty {
// Zero is our default value that means to inherit the font size.
config.font_size = fontSize ?? 0
// Set wait after command
config.wait_after_command = waitAfterCommand
// Use withCString to ensure strings remain valid for the duration of the closure
return try workingDirectory.withCString { cWorkingDir in

View File

@@ -41,6 +41,23 @@ extension Ghostty {
// The hovered URL string
@Published var hoverUrl: String? = nil
// The progress report (if any)
@Published var progressReport: Action.ProgressReport? = nil {
didSet {
// Cancel any existing timer
progressReportTimer?.invalidate()
progressReportTimer = nil
// If we have a new progress report, start a timer to remove it after 15 seconds
if progressReport != nil {
progressReportTimer = Timer.scheduledTimer(withTimeInterval: 15.0, repeats: false) { [weak self] _ in
self?.progressReport = nil
self?.progressReportTimer = nil
}
}
}
}
// The currently active key sequence. The sequence is not active if this is empty.
@Published var keySequence: [KeyboardShortcut] = []
@@ -142,6 +159,9 @@ extension Ghostty {
// A timer to fallback to ghost emoji if no title is set within the grace period
private var titleFallbackTimer: Timer?
// Timer to remove progress report after 15 seconds
private var progressReportTimer: Timer?
// This is the title from the terminal. This is nil if we're currently using
// the terminal title as the main title property. If the title is set manually
@@ -348,6 +368,9 @@ extension Ghostty {
// Remove any notifications associated with this surface
let identifiers = Array(self.notificationIdentifiers)
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: identifiers)
// Cancel progress report timer
progressReportTimer?.invalidate()
}
func focusDidChange(_ focused: Bool) {
@@ -1241,7 +1264,7 @@ extension Ghostty {
var key_ev = event.ghosttyKeyEvent(action, translationMods: translationEvent?.modifierFlags)
key_ev.composing = composing
// For text, we only encode UTF8 if we don't have a single control
// character. Control characters are encoded by Ghostty itself.
// Without this, `ctrl+enter` does the wrong thing.
@@ -1327,7 +1350,7 @@ extension Ghostty {
var item: NSMenuItem
// If we have a selection, add copy
if self.selectedRange().length > 0 {
if let text = self.accessibilitySelectedText(), text.count > 0 {
menu.addItem(withTitle: "Copy", action: #selector(copy(_:)), keyEquivalent: "")
}
menu.addItem(withTitle: "Paste", action: #selector(paste(_:)), keyEquivalent: "")
@@ -1519,6 +1542,8 @@ extension Ghostty {
enum CodingKeys: String, CodingKey {
case pwd
case uuid
case title
case isUserSetTitle
}
required convenience init(from decoder: Decoder) throws {
@@ -1533,14 +1558,27 @@ extension Ghostty {
let uuid = UUID(uuidString: try container.decode(String.self, forKey: .uuid))
var config = Ghostty.SurfaceConfiguration()
config.workingDirectory = try container.decode(String?.self, forKey: .pwd)
let savedTitle = try container.decodeIfPresent(String.self, forKey: .title)
let isUserSetTitle = try container.decodeIfPresent(Bool.self, forKey: .isUserSetTitle) ?? false
self.init(app, baseConfig: config, uuid: uuid)
// Restore the saved title after initialization
if let title = savedTitle {
self.title = title
// If this was a user-set title, we need to prevent it from being overwritten
if isUserSetTitle {
self.titleFromTerminal = title
}
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(pwd, forKey: .pwd)
try container.encode(uuid.uuidString, forKey: .uuid)
try container.encode(title, forKey: .title)
try container.encode(titleFromTerminal != nil, forKey: .isUserSetTitle)
}
}
}
@@ -1645,8 +1683,10 @@ extension Ghostty.SurfaceView: NSTextInputClient {
}
// Ghostty will tell us where it thinks an IME keyboard should render.
var x: Double = 0;
var y: Double = 0;
var x: Double = 0
var y: Double = 0
var width: Double = cellSize.width
var height: Double = cellSize.height
// QuickLook never gives us a matching range to our selection so if we detect
// this then we return the top-left selection point rather than the cursor point.
@@ -1664,15 +1704,19 @@ extension Ghostty.SurfaceView: NSTextInputClient {
// Free our text
ghostty_surface_free_text(surface, &text)
} else {
ghostty_surface_ime_point(surface, &x, &y)
ghostty_surface_ime_point(surface, &x, &y, &width, &height)
}
} else {
ghostty_surface_ime_point(surface, &x, &y)
ghostty_surface_ime_point(surface, &x, &y, &width, &height)
}
// Ghostty coordinates are in top-left (0, 0) so we have to convert to
// bottom-left since that is what UIKit expects
let viewRect = NSMakeRect(x, frame.size.height - y, 0, 0)
let viewRect = NSMakeRect(
x,
frame.size.height - y,
max(width, cellSize.width),
max(height, cellSize.height))
// Convert the point to the window coordinates
let winRect = self.convert(viewRect, to: nil)

View File

@@ -30,6 +30,9 @@ extension Ghostty {
// The hovered URL
@Published var hoverUrl: String? = nil
// The progress report (if any)
@Published var progressReport: Action.ProgressReport? = nil
// The time this surface last became focused. This is a ContinuousClock.Instant
// on supported platforms.

View File

@@ -407,8 +407,14 @@ class NonNativeFullscreen: FullscreenBase, FullscreenStyle {
self.styleMask = window.styleMask
self.toolbar = window.toolbar
self.toolbarStyle = window.toolbarStyle
self.titlebarAccessoryViewControllers = window.titlebarAccessoryViewControllers
self.dock = window.screen?.hasDock ?? false
self.titlebarAccessoryViewControllers = if (window.hasTitleBar) {
// Accessing titlebarAccessoryViewControllers without a titlebar triggers a crash.
window.titlebarAccessoryViewControllers
} else {
[]
}
if let cgWindowId = window.cgWindowId {
// We hide the menu only if this window is not on any fullscreen

View File

@@ -9,6 +9,7 @@
# - build.zig.zon.nix
# - build.zig.zon.txt
# - build.zig.zon.json
# - flatpak/zig-packages.json
#
# All of these are auto-generated and should not be edited manually.
@@ -34,8 +35,8 @@ help() {
echo "commit, and submit a PR with the update:"
echo ""
echo " ./nix/build-support/check-zig-cache-hash.sh --update"
echo " git add build.zig.zon.nix build.zig.zon.txt build.zig.zon.json"
echo " git commit -m \"nix: update build.zig.zon.nix build.zig.zon.txt build.zig.zon.json\""
echo " git add build.zig.zon.nix build.zig.zon.txt build.zig.zon.json flatpak/zig-packages.json"
echo " git commit -m \"nix: update build.zig.zon.nix build.zig.zon.txt build.zig.zon.json flatpak/zig-packages.json\""
echo ""
}
@@ -44,6 +45,7 @@ BUILD_ZIG_ZON="$ROOT/build.zig.zon"
BUILD_ZIG_ZON_NIX="$ROOT/build.zig.zon.nix"
BUILD_ZIG_ZON_TXT="$ROOT/build.zig.zon.txt"
BUILD_ZIG_ZON_JSON="$ROOT/build.zig.zon.json"
ZIG_PACKAGES_JSON="$ROOT/flatpak/zig-packages.json"
if [ -f "${BUILD_ZIG_ZON_NIX}" ]; then
OLD_HASH_NIX=$(sha512sum "${BUILD_ZIG_ZON_NIX}" | awk '{print $1}')
@@ -69,27 +71,40 @@ 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"
if [ -f "${ZIG_PACKAGES_JSON}" ]; then
OLD_HASH_FLATPAK=$(sha512sum "${ZIG_PACKAGES_JSON}" | awk '{print $1}')
elif [ "$1" != "--update" ]; then
echo -e "\nERROR: flatpak/zig-packages.json missing."
help
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"
alejandra --quiet "$WORK_DIR/build.zig.zon.nix"
prettier --write "$WORK_DIR/build.zig.zon.json"
prettier --log-level warn --write "$WORK_DIR/build.zig.zon.json"
prettier --log-level warn --write "$WORK_DIR/zig-packages.json"
NEW_HASH_NIX=$(sha512sum "$WORK_DIR/build.zig.zon.nix" | awk '{print $1}')
NEW_HASH_TXT=$(sha512sum "$WORK_DIR/build.zig.zon.txt" | awk '{print $1}')
NEW_HASH_JSON=$(sha512sum "$WORK_DIR/build.zig.zon.json" | awk '{print $1}')
NEW_HASH_FLATPAK=$(sha512sum "$WORK_DIR/zig-packages.json" | awk '{print $1}')
if [ "${OLD_HASH_NIX}" == "${NEW_HASH_NIX}" ] && [ "${OLD_HASH_TXT}" == "${NEW_HASH_TXT}" ] && [ "${OLD_HASH_JSON}" == "${NEW_HASH_JSON}" ]; then
if [ "${OLD_HASH_NIX}" == "${NEW_HASH_NIX}" ] && [ "${OLD_HASH_TXT}" == "${NEW_HASH_TXT}" ] && [ "${OLD_HASH_JSON}" == "${NEW_HASH_JSON}" ] && [ "${OLD_HASH_FLATPAK}" == "${NEW_HASH_FLATPAK}" ]; then
echo -e "\nOK: build.zig.zon.nix unchanged."
echo -e "OK: build.zig.zon.txt unchanged."
echo -e "OK: build.zig.zon.json unchanged."
echo -e "OK: flatpak/zig-packages.json unchanged."
exit 0
elif [ "$1" != "--update" ]; then
echo -e "\nERROR: build.zig.zon.nix, build.zig.zon.txt, or build.zig.zon.json needs to be updated.\n"
echo " * Old build.zig.zon.nix hash: ${OLD_HASH_NIX}"
echo " * New build.zig.zon.nix hash: ${NEW_HASH_NIX}"
echo " * Old build.zig.zon.txt hash: ${OLD_HASH_TXT}"
echo " * New build.zig.zon.txt hash: ${NEW_HASH_TXT}"
echo " * Old build.zig.zon.json hash: ${OLD_HASH_JSON}"
echo " * New build.zig.zon.json hash: ${NEW_HASH_JSON}"
echo " * Old build.zig.zon.nix hash: ${OLD_HASH_NIX}"
echo " * New build.zig.zon.nix hash: ${NEW_HASH_NIX}"
echo " * Old build.zig.zon.txt hash: ${OLD_HASH_TXT}"
echo " * New build.zig.zon.txt hash: ${NEW_HASH_TXT}"
echo " * Old build.zig.zon.json hash: ${OLD_HASH_JSON}"
echo " * New build.zig.zon.json hash: ${NEW_HASH_JSON}"
echo " * Old flatpak/zig-packages.json hash: ${OLD_HASH_FLATPAK}"
echo " * New flatpak/zig-packages.json hash: ${NEW_HASH_FLATPAK}"
help
exit 1
else
@@ -99,6 +114,8 @@ else
echo -e "OK: build.zig.zon.txt updated."
mv "$WORK_DIR/build.zig.zon.json" "$BUILD_ZIG_ZON_JSON"
echo -e "OK: build.zig.zon.json updated."
mv "$WORK_DIR/zig-packages.json" "$ZIG_PACKAGES_JSON"
echo -e "OK: flatpak/zig-packages.json updated."
exit 0
fi

View File

@@ -69,6 +69,10 @@
zon2nix,
system,
pkgs,
# needed by GTK for loading SVG icons while running from within the
# developer shell
glycin-loaders,
librsvg,
}: let
# See package.nix. Keep in sync.
ld_library_path = import ./build-support/ld-library-path.nix {
@@ -174,6 +178,11 @@ in
gst_all_1.gstreamer
gst_all_1.gst-plugins-base
gst_all_1.gst-plugins-good
# needed by GTK for loading SVG icons while running from within the
# developer shell
glycin-loaders
librsvg
];
# This should be set onto the rpath of the ghostty binary if you want

View File

@@ -13,11 +13,7 @@ pub fn build(b: *std.Build) !void {
const unit_tests = b.addTest(.{
.name = "test",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
.root_module = module,
});
unit_tests.linkLibC();
@@ -34,12 +30,6 @@ pub fn build(b: *std.Build) !void {
.file = wuffs_dep.path("release/c/wuffs-v0.4.c"),
.flags = flags.items,
});
unit_tests.addIncludePath(wuffs_dep.path("release/c"));
unit_tests.addCSourceFile(.{
.file = wuffs_dep.path("release/c/wuffs-v0.4.c"),
.flags = flags.items,
});
}
if (b.lazyDependency("pixels", .{})) |pixels_dep| {

View File

@@ -2,14 +2,15 @@
# Copyright (C) 2025 Mitchell Hashimoto
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# Damyan Bogoev <damyan.bogoev@gmail.com>, 2025.
# reo101 <pavel.atanasov2001@gmail.com>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-05-19 11:34+0300\n"
"Last-Translator: Damyan Bogoev <damyan.bogoev@gmail.com>\n"
"PO-Revision-Date: 2025-08-22 14:52+0300\n"
"Last-Translator: reo101 <pavel.atanasov2001@gmail.com>\n"
"Language-Team: Bulgarian <dict@ludost.net>\n"
"Language: bg\n"
"MIME-Version: 1.0\n"
@@ -208,12 +209,12 @@ msgstr "Позволи"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Запомни избора за това разделяне"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "За да покажеш това съобщение отново, презареди конфигурацията"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -278,15 +279,15 @@ msgstr "Копирано в клипборда"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Клипбордът е изчистен"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Командата завърши успешно"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Командата завърши неуспешно"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"

View File

@@ -2,14 +2,15 @@
# Copyright (C) 2025 Mitchell Hashimoto, Ghostty contributors
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# Francesc Arpi <francesc.arpi@gmail.com>, 2025.
# Kristofer Soler <31729650+KristoferSoler@users.noreply.github.com>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-03-20 08:07+0100\n"
"Last-Translator: Francesc Arpi <francesc.arpi@gmail.com>\n"
"PO-Revision-Date: 2025-08-24 19:22+0200\n"
"Last-Translator: Kristofer Soler <31729650+KristoferSoler@users.noreply.github.com>\n"
"Language-Team: \n"
"Language: ca\n"
"MIME-Version: 1.0\n"
@@ -87,7 +88,7 @@ msgstr "Divideix a la dreta"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Executa una ordre…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -160,7 +161,7 @@ msgstr "Obre la configuració"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Paleta de comandes"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -208,12 +209,12 @@ msgstr "Permet"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Recorda lopció per a aquest panell dividit"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Recarrega la configuració per tornar a mostrar aquest missatge"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -278,15 +279,15 @@ msgstr "Copiat al porta-retalls"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Porta-retalls netejat"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Comanda completada amb èxit"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Comanda fallida"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
@@ -298,7 +299,7 @@ msgstr "Mostra les pestanyes obertes"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
msgstr "Nova divisió"
#: src/apprt/gtk/Window.zig:329
msgid ""

View File

@@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-03-06 14:57+0100\n"
"PO-Revision-Date: 2025-08-25 19:38+0100\n"
"Last-Translator: Robin <r@rpfaeffle.com>\n"
"Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
"Language: de\n"
@@ -39,7 +39,7 @@ msgstr "OK"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr ""
msgstr "Konfigurationsfehler"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
@@ -47,11 +47,14 @@ msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
msgstr ""
"Ein oder mehrere Konfigurationsfehler wurden gefunden. Bitte überprüfe "
"die untenstehenden Fehler und lade entweder deine Konfiguration erneut oder "
"ignoriere die Fehler."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr ""
msgstr "Ignorieren"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
@@ -86,7 +89,7 @@ msgstr "Fenster nach rechts teilen"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Einen Befehl ausführen…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -159,7 +162,7 @@ msgstr "Konfiguration öffnen"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Befehlspalette"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -207,12 +210,13 @@ msgstr "Erlauben"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Auswahl für dieses geteilte Fenster beibehalten"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
"Lade die Konfiguration erneut, um diese Eingabeaufforderung erneut anzuzeigen"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -277,15 +281,15 @@ msgstr "In die Zwischenablage kopiert"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Zwischenablage geleert"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Befehl erfolgreich"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Befehl fehlgeschlagen"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
@@ -297,7 +301,7 @@ msgstr "Offene Tabs einblenden"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
msgstr "Neues geteiltes Fenster"
#: src/apprt/gtk/Window.zig:329
msgid ""

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-05-19 20:17-0300\n"
"PO-Revision-Date: 2025-08-22 09:35-0300\n"
"Last-Translator: Alan Moyano <alanmoyano203@gmail.com>\n"
"Language-Team: Argentinian <es@tp.org.es>\n"
"Language: es_AR\n"
@@ -208,12 +208,12 @@ msgstr "Permitir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Recordar elección para esta división"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Recargar la configuración para volver a mostrar este mensaje"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -278,15 +278,15 @@ msgstr "Copiado al portapapeles"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Portapapeles limpiado"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Comando ejecutado correctamente"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "El comando ha fallado"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-03-28 17:46+0200\n"
"PO-Revision-Date: 2025-08-23 17:46+0200\n"
"Last-Translator: Miguel Peredo <miguelp@quientienemail.com>\n"
"Language-Team: Spanish <es@tp.org.es>\n"
"Language: es_BO\n"
@@ -87,7 +87,7 @@ msgstr "Dividir a la derecha"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Ejecutar comando..."
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -160,7 +160,7 @@ msgstr "Abrir configuración"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Paleta de comandos"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -208,12 +208,12 @@ msgstr "Permitir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Recordar su elección para esta división de ventana"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Recargar configuración para mostrar este aviso nuevamente"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -278,15 +278,15 @@ msgstr "Copiado al portapapeles"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "El portapapeles está limpio"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Comando ejecutado con éxito"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Comando fallido"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
@@ -298,7 +298,7 @@ msgstr "Ver pestañas abiertas"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
msgstr "Nueva ventana dividida"
#: src/apprt/gtk/Window.zig:329
msgid ""

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-03-22 09:31+0100\n"
"PO-Revision-Date: 2025-08-23 21:01+0200\n"
"Last-Translator: Kirwiisp <swiip__@hotmail.com>\n"
"Language-Team: French <traduc@traduc.org>\n"
"Language: fr\n"
@@ -88,7 +88,7 @@ msgstr "Panneau à droite"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Exécuter une commande…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -161,7 +161,7 @@ msgstr "Ouvrir la configuration"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Palette de commandes"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -209,12 +209,12 @@ msgstr "Autoriser"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Se rappeler du choix pour ce panneau"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Recharger la configuration pour afficher à nouveau ce message"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -279,15 +279,15 @@ msgstr "Copié dans le presse-papiers"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Presse-papiers vidé"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Commande réussie"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "La commande a échoué"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
@@ -299,7 +299,7 @@ msgstr "Voir les onglets ouverts"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
msgstr "Nouveau panneau"
#: src/apprt/gtk/Window.zig:329
msgid ""

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-06-29 21:15+0100\n"
"PO-Revision-Date: 2025-08-26 15:46+0100\n"
"Last-Translator: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>\n"
"Language-Team: Irish <gaeilge-gnulinux@lists.sourceforge.net>\n"
"Language: ga\n"
@@ -16,7 +16,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;\n"
"X-Generator: Poedit 3.4.4\n"
"X-Generator: Poedit 3.4.2\n"
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:5
msgid "Change Terminal Title"
@@ -209,12 +209,12 @@ msgstr "Ceadaigh"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Sábháil an rogha don scoilt seo"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Athlódáil an chumraíocht chun an teachtaireacht seo a thaispeáint arís"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -280,15 +280,15 @@ msgstr "Cóipeáilte chuig an ghearrthaisce"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Gearrthaisce glanta"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "D'éirigh leis an ordú"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Theip ar an ordú"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"

View File

@@ -2,15 +2,15 @@
# Copyright (C) 2025 Mitchell Hashimoto
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# Sl (Shahaf Levi), Sl's Repository Ltd <ghostty@slsrepo.com>, 2025.
# CraziestOwl <craziestowl@proton.me>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-03-13 00:00+0000\n"
"Last-Translator: Sl (Shahaf Levi), Sl's Repository Ltd <ghostty@slsrepo."
"com>\n"
"PO-Revision-Date: 2025-08-23 08:00+0300\n"
"Last-Translator: CraziestOwl <craziestowl@proton.me>\n"
"Language-Team: Hebrew <he_IL@lists.sourceforge.net>\n"
"Language: he\n"
"MIME-Version: 1.0\n"
@@ -276,15 +276,15 @@ msgstr "הועתק ללוח ההעתקה"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "לוח ההעתקה רוקן"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "הפקודה הצליחה"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "הפקודה נכשלה"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"

320
po/hu_HU.UTF-8.po Normal file
View File

@@ -0,0 +1,320 @@
# Hungarian translations for com.mitchellh.ghostty package.
# Copyright (C) 2025 Mitchell Hashimoto
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# Balázs Szücs <bszucs1209@gmail.com>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-08-23 17:14+0200\n"
"Last-Translator: Balázs Szücs <bszucs1209@gmail.com>\n"
"Language-Team: Hungarian <translation-team-hu@lists.sourceforge.net>\n"
"Language: hu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:5
msgid "Change Terminal Title"
msgstr "Terminál címének módosítása"
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:6
msgid "Leave blank to restore the default title."
msgstr "Hagyja üresen az alapértelmezett cím visszaállításához."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Mégse"
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:10
msgid "OK"
msgstr "Rendben"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Konfigurációs hibák"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
msgstr ""
"Egy vagy több konfigurációs hiba található. Kérjük, ellenőrizze az alábbi "
"hibákat, és frissítse a konfigurációt, vagy hagyja figyelmen kívül ezeket a "
"hibákat."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
msgid "Ignore"
msgstr "Figyelmen kívül hagyás"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:10
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:97
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Konfiguráció frissítése"
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:38
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:50
msgid "Split Up"
msgstr "Felosztás felfelé"
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:43
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:55
msgid "Split Down"
msgstr "Felosztás lefelé"
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:16
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:48
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:60
msgid "Split Left"
msgstr "Felosztás balra"
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:21
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:53
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:65
msgid "Split Right"
msgstr "Felosztás jobbra"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr "Parancs végrehajtása…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
msgid "Copy"
msgstr "Másolás"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:11
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:11 src/apprt/gtk/ui/1.2/ccw-paste.blp:11
msgid "Paste"
msgstr "Beillesztés"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:18
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:73
msgid "Clear"
msgstr "Törlés"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:23
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:78
msgid "Reset"
msgstr "Visszaállítás"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:30
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:42
msgid "Split"
msgstr "Felosztás"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:33
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:45
msgid "Change Title…"
msgstr "Cím módosítása…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:59
msgid "Tab"
msgstr "Fül"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:62
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:30
#: src/apprt/gtk/Window.zig:265
msgid "New Tab"
msgstr "Új fül"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:67
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:35
msgid "Close Tab"
msgstr "Fül bezárása"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:73
msgid "Window"
msgstr "Ablak"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:76
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:18
msgid "New Window"
msgstr "Új ablak"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:81
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:23
msgid "Close Window"
msgstr "Ablak bezárása"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:89
msgid "Config"
msgstr "Konfiguráció"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Konfiguráció megnyitása"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr "Parancspaletta"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
msgstr "Terminálvizsgáló"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:107
#: src/apprt/gtk/Window.zig:1038
msgid "About Ghostty"
msgstr "A Ghostty névjegye"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:112
msgid "Quit"
msgstr "Kilépés"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Vágólap-hozzáférés engedélyezése"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
msgstr ""
"Egy alkalmazás megpróbál olvasni a vágólapról. A vágólap jelenlegi tartalma "
"lent látható."
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Elutasítás"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:11
msgid "Allow"
msgstr "Engedélyezés"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr "Választás megjegyzése erre a felosztásra"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr "Konfiguráció frissítése a kérdés újbóli megjelenítéséhez"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
msgstr ""
"Egy alkalmazás megpróbál írni a vágólapra. A vágólap jelenlegi tartalma lent "
"látható."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Figyelem: potenciálisan veszélyes beillesztés"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
msgstr ""
"Ennek a szövegnek a terminálba való beillesztése veszélyes lehet, mivel "
"néhány parancs végrehajtásra kerülhet."
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2531
msgid "Close"
msgstr "Bezárás"
#: src/apprt/gtk/CloseDialog.zig:87
msgid "Quit Ghostty?"
msgstr "Kilép a Ghostty-ból?"
#: src/apprt/gtk/CloseDialog.zig:88
msgid "Close Window?"
msgstr "Ablak bezárása?"
#: src/apprt/gtk/CloseDialog.zig:89
msgid "Close Tab?"
msgstr "Fül bezárása?"
#: src/apprt/gtk/CloseDialog.zig:90
msgid "Close Split?"
msgstr "Felosztás bezárása?"
#: src/apprt/gtk/CloseDialog.zig:96
msgid "All terminal sessions will be terminated."
msgstr "Minden terminál munkamenet lezárul."
#: src/apprt/gtk/CloseDialog.zig:97
msgid "All terminal sessions in this window will be terminated."
msgstr "Ebben az ablakban minden terminál munkamenet lezárul."
#: src/apprt/gtk/CloseDialog.zig:98
msgid "All terminal sessions in this tab will be terminated."
msgstr "Ezen a fülön minden terminál munkamenet lezárul."
#: src/apprt/gtk/CloseDialog.zig:99
msgid "The currently running process in this split will be terminated."
msgstr "Ebben a felosztásban a jelenleg futó folyamat lezárul."
#: src/apprt/gtk/Surface.zig:1266
msgid "Copied to clipboard"
msgstr "Vágólapra másolva"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr "Vágólap törölve"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr "Parancs sikeres"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr "Parancs sikertelen"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
msgstr "Főmenü"
#: src/apprt/gtk/Window.zig:239
msgid "View Open Tabs"
msgstr "Megnyitott fülek megtekintése"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr "Új felosztás"
#: src/apprt/gtk/Window.zig:329
msgid ""
"⚠️ You're running a debug build of Ghostty! Performance will be degraded."
msgstr ""
"⚠️ A Ghostty hibakereső verzióját futtatja! A teljesítmény csökkenni fog."
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Konfiguráció frissítve"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"
msgstr "Ghostty fejlesztők"
#: src/apprt/gtk/inspector.zig:144
msgid "Ghostty: Terminal Inspector"
msgstr "Ghostty: Terminálvizsgáló"

View File

@@ -2,14 +2,15 @@
# Copyright (C) 2025 Mitchell Hashimoto, Ghostty contributors
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# Satrio Bayu Aji <halosatrio@gmail.com>, 2025.
# Mikail Muzakki <mikailmmuzakki@gmail.com>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-03-20 15:19+0700\n"
"Last-Translator: Satrio Bayu Aji <halosatrio@gmail.com>\n"
"PO-Revision-Date: 2025-08-01 10:15+0700\n"
"Last-Translator: Mikail Muzakki <mikailmmuzakki@gmail.com>\n"
"Language-Team: Indonesian <translation-team-id@lists.sourceforge.net>\n"
"Language: id\n"
"MIME-Version: 1.0\n"
@@ -86,7 +87,7 @@ msgstr "Belah kanan"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Eksekusi perintah…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -102,7 +103,7 @@ msgstr "Tempel"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:18
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:73
msgid "Clear"
msgstr "Hapus"
msgstr "Bersihkan"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:23
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:78
@@ -159,7 +160,7 @@ msgstr "Buka konfigurasi"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Palet perintah"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -195,7 +196,7 @@ msgstr ""
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Menyangkal"
msgstr "Tolak"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
@@ -207,12 +208,12 @@ msgstr "Izinkan"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Ingat pilihan untuk belahan ini"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Muat ulang konfigurasi untuk menampilkan pesan ini lagi"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -225,7 +226,7 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
msgstr "Peringatan: Tempelan yang berpotensi tidak aman"
msgstr "Peringatan: Tempelan berpotensi tidak aman"
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:7 src/apprt/gtk/ui/1.2/ccw-paste.blp:7
msgid ""
@@ -277,15 +278,15 @@ msgstr "Disalin ke papan klip"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Papan klip dibersihkan"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Perintah berhasil"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Perintah gagal"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
@@ -297,7 +298,7 @@ msgstr "Lihat tab terbuka"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
msgstr "Belahan baru"
#: src/apprt/gtk/Window.zig:329
msgid ""

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-07-09 16:11-0400\n"
"Last-Translator: Hojin You <dev.hojin@gmail.com>\n"
"PO-Revision-Date: 2025-08-03 20:42+0900\n"
"Last-Translator: Jinhyeok Lee <zenyr@zenyr.com>\n"
"Language-Team: Korean <translation-team-ko@googlegroups.com>\n"
"Language: ko\n"
"MIME-Version: 1.0\n"
@@ -46,7 +46,7 @@ msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
msgstr ""
"설정에 하나 이상의 문제가 발견되었습니다. 아래 오류(를)들을 확인한 후 설정을 "
"설정에 하나 이상의 문제가 발견되었습니다. 아래 오류 확인한 후 설정을 "
"다시 불러오거나 무시하세요."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
@@ -232,9 +232,7 @@ msgstr "경고: 잠재적으로 안전하지 않은 붙여넣기"
msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
msgstr ""
"이 텍스트를 터미널에 붙여넣는 것은 위험할 수 있습니다. 일부 명령이 실행될 수 "
"있는 것으로 보입니다."
msgstr "이 텍스트를 터미널에 붙여넣으면 일부 명령이 실행될 수 있어 위험할 수 있습니다."
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2531
msgid "Close"
@@ -278,15 +276,15 @@ msgstr "클립보드에 복사됨"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "클립보드 지워짐"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "명령 성공"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "명령 실패"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"

View File

@@ -2,14 +2,15 @@
# Copyright (C) 2025 Mitchell Hashimoto, Ghostty contributors
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# Andrej Daskalov <andrej.daskalov@gmail.com>, 2025.
# Marija Gjorgjieva Gjondeva <mgjorgjieva2013@gmail.com>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-03-23 14:17+0100\n"
"Last-Translator: Andrej Daskalov <andrej.daskalov@gmail.com>\n"
"PO-Revision-Date: 2025-08-25 22:17+0200\n"
"Last-Translator: Marija Gjorgjieva Gjondeva <mgjorgjieva2013@gmail.com>\n"
"Language-Team: Macedonian\n"
"Language: mk\n"
"MIME-Version: 1.0\n"
@@ -87,7 +88,7 @@ msgstr "Подели надесно"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Изврши команда…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -160,7 +161,7 @@ msgstr "Отвори конфигурација"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Командна палета"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -208,12 +209,12 @@ msgstr "Дозволи"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Запомни го изборот за оваа поделба"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Одново вчитај конфигурација за да се повторно прикаже пораката"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -278,15 +279,15 @@ msgstr "Копирано во привремена меморија"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Исчистена привремена меморија"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Командата успеа"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Командата не успеа"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
@@ -298,7 +299,7 @@ msgstr "Прегледај отворени јазичиња"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
msgstr "Нова поделба"
#: src/apprt/gtk/Window.zig:329
msgid ""

View File

@@ -1,7 +1,7 @@
# Norwegian Bokmal translations for com.mitchellh.ghostty package.
# Copyright (C) 2025 Mitchell Hashimoto, Ghostty contributors
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# Hanna Rose <hanna@hanna.lol>, 2025.
# Hanna Rose <me@hanna.lol>, 2025.
# Uzair Aftab <uzaaft@outlook.com>, 2025.
# Christoffer Tønnessen <christoffer@cto.gg>, 2025.
# cryptocode <cryptocode@zolo.io>, 2025.
@@ -11,8 +11,8 @@ msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-04-14 16:25+0200\n"
"Last-Translator: cryptocode <cryptocode@zolo.io>\n"
"PO-Revision-Date: 2025-08-23 12:52+0000\n"
"Last-Translator: Hanna Rose <me@hanna.lol>\n"
"Language-Team: Norwegian Bokmal <l10n-no@lister.huftis.org>\n"
"Language: nb\n"
"MIME-Version: 1.0\n"
@@ -90,7 +90,7 @@ msgstr "Del til høyre"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Kjør en kommando..."
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -163,7 +163,7 @@ msgstr "Åpne konfigurasjon"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Kommandopalett"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -211,12 +211,12 @@ msgstr "Tillat"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Husk valget for dette delte vinduet?"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Last inn konfigurasjonen på nytt for å vise denne meldingen igjen"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -281,15 +281,15 @@ msgstr "Kopiert til utklippstavlen"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Utklippstavle tømt"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Kommando lyktes"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Kommando mislyktes"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"

View File

@@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-07-12 08:54+0200\n"
"PO-Revision-Date: 2025-07-23 22:36+0200\n"
"Last-Translator: Merijntje Tak <merijntje@tak.io>\n"
"Language-Team: Dutch <vertaling@vrijschrift.org>\n"
"Language: nl\n"
@@ -279,7 +279,7 @@ msgstr "Gekopieerd naar klembord"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Klembord geleegd"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"

View File

@@ -3,14 +3,15 @@
# Copyright (C) 2025 Mitchell Hashimoto, Ghostty contributors
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# Bartosz Sokorski <b.sokorski@gmail.com>, 2025.
# trag1c <dev@jakubr.me>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-03-17 12:15+0100\n"
"Last-Translator: Bartosz Sokorski <b.sokorski@gmail.com>\n"
"PO-Revision-Date: 2025-08-05 16:27+0200\n"
"Last-Translator: trag1c <dev@jakubr.me>\n"
"Language-Team: Polish <translation-team-pl@lists.sourceforge.net>\n"
"Language: pl\n"
"MIME-Version: 1.0\n"
@@ -89,7 +90,7 @@ msgstr "Podziel w prawo"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Wykonaj komendę…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -162,7 +163,7 @@ msgstr "Otwórz konfigurację"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Paleta komend"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -210,12 +211,12 @@ msgstr "Zezwól"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Zapamiętaj wybór dla tego podziału"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Przeładuj konfigurację, by ponownie wyświetlić ten komunikat"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -280,15 +281,15 @@ msgstr "Skopiowano do schowka"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Wyczyszczono schowek"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Komenda wykonana pomyślnie"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Komenda nie powiodła się"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
@@ -300,7 +301,7 @@ msgstr "Zobacz otwarte karty"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
msgstr "Nowy podział"
#: src/apprt/gtk/Window.zig:329
msgid ""

View File

@@ -3,14 +3,15 @@
# Copyright (C) 2025 Mitchell Hashimoto, Ghostty contributors
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# Gustavo Peres <gsodevel@gmail.com>, 2025.
# Guilherme Tiscoski <github@guilhermetiscoski.com>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-06-20 10:19-0300\n"
"Last-Translator: Mário Victor Ribeiro Silva <mariovictorrs@gmail.com>\n"
"PO-Revision-Date: 2025-08-25 11:46-0500\n"
"Last-Translator: Guilherme Tiscoski <github@guihermetiscoski.com>\n"
"Language-Team: Brazilian Portuguese <ldpbr-translation@lists.sourceforge."
"net>\n"
"Language: pt_BR\n"
@@ -89,7 +90,7 @@ msgstr "Dividir à direita"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Executar um comando…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -162,7 +163,7 @@ msgstr "Abrir configuração"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Paleta de comandos"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -210,12 +211,12 @@ msgstr "Permitir"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Lembrar escolha para esta divisão"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Recarregue a configuração para mostrar este aviso novamente"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -280,15 +281,15 @@ msgstr "Copiado para a área de transferência"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Área de transferência limpa"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Comando executado com sucesso"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Comando falhou"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"

View File

@@ -3,15 +3,16 @@
# Copyright (C) 2025 Mitchell Hashimoto, Ghostty contributors
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# blackzeshi <sergey_zhuzhgov@mail.ru>, 2025.
#
# Ivan Bastrakov <bastaynav@proton.me>, 2025.
msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-03-24 00:01+0500\n"
"Last-Translator: blackzeshi <sergey_zhuzhgov@mail.ru>\n"
"Language-Team: Russian <gnu@d07.ru>\n"
"PO-Revision-Date: 2025-09-03 01:50+0300\n"
"Last-Translator: Ivan Bastrakov <bastaynav@proton.me>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -89,7 +90,7 @@ msgstr "Сплит вправо"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Выполнить команду…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -162,7 +163,7 @@ msgstr "Открыть конфигурационный файл"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Палитра команд"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -210,12 +211,12 @@ msgstr "Разрешить"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Запомнить выбор для этого сплита"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Перезагрузите конфигурацию, чтобы снова увидеть это сообщение"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -223,7 +224,8 @@ msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
msgstr ""
"Приложение пытается записать данные в буфер обмена. Эти данные показаны ниже."
"Приложение пытается записать данные в буфер обмена. Текущее содержимое "
"буфера обмена показано ниже."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
@@ -279,15 +281,15 @@ msgstr "Скопировано в буфер обмена"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Буфер обмена очищен"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Команда выполнена успешно"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Команда завершилась с ошибкой"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
@@ -299,7 +301,7 @@ msgstr "Просмотреть открытые вкладки"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
msgstr "Новый сплит"
#: src/apprt/gtk/Window.zig:329
msgid ""

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-03-24 22:01+0300\n"
"PO-Revision-Date: 2025-08-23 17:30+0300\n"
"Last-Translator: Emir SARI <emir_sari@icloud.com>\n"
"Language-Team: Turkish\n"
"Language: tr\n"
@@ -88,7 +88,7 @@ msgstr "Sağa Doğru Böl"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Bir komut çalıştır…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -161,7 +161,7 @@ msgstr "Yapılandırmayı Aç"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Komut Paleti"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -209,12 +209,12 @@ msgstr "İzin Ver"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Bu bölme için tercihi anımsa"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Bu istemi tekrar göstermek için yapılandırmayı yeniden yükle"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -279,15 +279,15 @@ msgstr "Panoya kopyalandı"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Pano temizlendi"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Komut başarılı oldu"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Komut başarısız oldu"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"

View File

@@ -2,14 +2,15 @@
# Copyright (C) 2025 Mitchell Hashimoto, Ghostty contributors
# This file is distributed under the same license as the com.mitchellh.ghostty package.
# Danylo Zalizchuk <danilmail0110@gmail.com>, 2025.
# Volodymyr Chernetskyi <19735328+chernetskyi@users.noreply.github.com>, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: com.mitchellh.ghostty\n"
"Report-Msgid-Bugs-To: m@mitchellh.com\n"
"POT-Creation-Date: 2025-07-22 17:18+0000\n"
"PO-Revision-Date: 2025-03-16 20:16+0200\n"
"Last-Translator: Danylo Zalizchuk <danilmail0110@gmail.com>\n"
"PO-Revision-Date: 2025-08-25 19:59+0100\n"
"Last-Translator: Volodymyr Chernetskyi <19735328+chernetskyi@users.noreply.github.com>\n"
"Language-Team: Ukrainian <trans-uk@lists.fedoraproject.org>\n"
"Language: uk\n"
"MIME-Version: 1.0\n"
@@ -20,17 +21,17 @@ msgstr ""
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:5
msgid "Change Terminal Title"
msgstr "Змінити назву терміналу"
msgstr "Змінити заголовок терміналу"
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:6
msgid "Leave blank to restore the default title."
msgstr "Залиште порожнім, щоб відновити назву за замовчуванням."
msgstr "Залиште порожнім, щоб відновити заголовок за замовчуванням."
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:9
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:10 src/apprt/gtk/ui/1.2/ccw-paste.blp:10
#: src/apprt/gtk/CloseDialog.zig:44
msgid "Cancel"
msgstr "Відмінити"
msgstr "Скасувати"
#: src/apprt/gtk/ui/1.5/prompt-title-dialog.blp:10
msgid "OK"
@@ -39,7 +40,7 @@ msgstr "ОК"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:5
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:5
msgid "Configuration Errors"
msgstr "Помилки конфігурації"
msgstr "Помилки налаштування"
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:6
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:6
@@ -47,9 +48,8 @@ msgid ""
"One or more configuration errors were found. Please review the errors below, "
"and either reload your configuration or ignore these errors."
msgstr ""
"Виявлено одну або декілька помилок у конфігурації. Будь ласка, перегляньте "
"наведені нижче помилки і або перезавантажте конфігурацію, або проігноруйте "
"ці помилки."
"Виявлено одну або декілька помилок налаштування. Будь ласка, перегляньте "
"помилки нижче і або перезавантажте налаштування, або проігноруйте ці помилки."
#: src/apprt/gtk/ui/1.5/config-errors-dialog.blp:9
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:9
@@ -61,35 +61,35 @@ msgstr "Ігнорувати"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:100
#: src/apprt/gtk/ui/1.2/config-errors-dialog.blp:10
msgid "Reload Configuration"
msgstr "Перезавантажити конфігурацію"
msgstr "Перезавантажити налаштування"
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:38
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:50
msgid "Split Up"
msgstr "Розділити панель вгору"
msgstr "Нова панель зверху"
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:11
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:43
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:55
msgid "Split Down"
msgstr "Розділити панель вниз"
msgstr "Нова панель знизу"
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:16
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:48
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:60
msgid "Split Left"
msgstr "Розділити панель ліворуч"
msgstr "Нова панель ліворуч"
#: src/apprt/gtk/ui/1.0/menu-headerbar-split_menu.blp:21
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:53
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:65
msgid "Split Right"
msgstr "Розділити панель праворуч"
msgstr "Нова панель праворуч"
#: src/apprt/gtk/ui/1.5/command-palette.blp:16
msgid "Execute a command…"
msgstr ""
msgstr "Виконати команду…"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:6
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:6
@@ -115,7 +115,7 @@ msgstr "Скинути"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:30
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:42
msgid "Split"
msgstr "Розділена панель"
msgstr "Панель"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:33
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:45
@@ -153,16 +153,16 @@ msgstr "Закрити вікно"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:89
msgid "Config"
msgstr "Конфігурація"
msgstr "Налаштування"
#: src/apprt/gtk/ui/1.0/menu-surface-context_menu.blp:92
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:95
msgid "Open Configuration"
msgstr "Відкрити конфігурацію"
msgstr "Відкрити налаштування"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:85
msgid "Command Palette"
msgstr ""
msgstr "Палітра команд"
#: src/apprt/gtk/ui/1.0/menu-window-titlebar_menu.blp:90
msgid "Terminal Inspector"
@@ -182,7 +182,7 @@ msgstr "Завершити"
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:6
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:6
msgid "Authorize Clipboard Access"
msgstr "Дозволити доступ до буфера обміну"
msgstr "Надати доступ до буфера обміну"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:7
@@ -190,15 +190,15 @@ msgid ""
"An application is attempting to read from the clipboard. The current "
"clipboard contents are shown below."
msgstr ""
"Програма намагається прочитати дані з буфера обміну. Нижче показано поточний "
"вміст буфера обміну."
"Програма намагається прочитати дані з буфера обміну. Нижче наведено вміст "
"буфера обміну."
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-read.blp:10
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:10
msgid "Deny"
msgstr "Відхилити"
msgstr "Заборонити"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:11
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:11
@@ -210,12 +210,12 @@ msgstr "Дозволити"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:81
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:77
msgid "Remember choice for this split"
msgstr ""
msgstr "Запамʼятати для цієї панелі"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-read.blp:82
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:78
msgid "Reload configuration to show this prompt again"
msgstr ""
msgstr "Перезавантажте налаштування, щоб показати це повідомлення знову"
#: src/apprt/gtk/ui/1.5/ccw-osc-52-write.blp:7
#: src/apprt/gtk/ui/1.2/ccw-osc-52-write.blp:7
@@ -223,8 +223,8 @@ msgid ""
"An application is attempting to write to the clipboard. The current "
"clipboard contents are shown below."
msgstr ""
"Програма намагається записати дані до буфера обміну. Нижче показано поточний "
"вміст буфера обміну."
"Програма намагається записати дані до буфера обміну. Нижче наведено вміст "
"буфера обміну."
#: src/apprt/gtk/ui/1.5/ccw-paste.blp:6 src/apprt/gtk/ui/1.2/ccw-paste.blp:6
msgid "Warning: Potentially Unsafe Paste"
@@ -235,8 +235,8 @@ msgid ""
"Pasting this text into the terminal may be dangerous as it looks like some "
"commands may be executed."
msgstr ""
"Вставка цього тексту в термінал може бути небезпечною, оскільки виглядає "
"так, ніби деякі команди можуть бути виконані."
"Вставка цього тексту в термінал може бути небезпечною, бо схоже, що деякі "
"команди можуть бути виконані."
#: src/apprt/gtk/CloseDialog.zig:47 src/apprt/gtk/Surface.zig:2531
msgid "Close"
@@ -256,7 +256,7 @@ msgstr "Закрити вкладку?"
#: src/apprt/gtk/CloseDialog.zig:90
msgid "Close Split?"
msgstr "Закрити розділену панель?"
msgstr "Закрити панель?"
#: src/apprt/gtk/CloseDialog.zig:96
msgid "All terminal sessions will be terminated."
@@ -272,24 +272,23 @@ msgstr "Всі сесії терміналу в цій вкладці будут
#: src/apprt/gtk/CloseDialog.zig:99
msgid "The currently running process in this split will be terminated."
msgstr ""
"Поточний процес, що виконується в цій розділеній панелі, буде завершено."
msgstr "Процес, що виконується в цій панелі, буде завершено."
#: src/apprt/gtk/Surface.zig:1266
msgid "Copied to clipboard"
msgstr "Скопійовано в буфер обміну"
msgstr "Скопійовано до буферa обміну"
#: src/apprt/gtk/Surface.zig:1268
msgid "Cleared clipboard"
msgstr ""
msgstr "Буфер обміну очищено"
#: src/apprt/gtk/Surface.zig:2525
msgid "Command succeeded"
msgstr ""
msgstr "Команда завершилась успішно"
#: src/apprt/gtk/Surface.zig:2527
msgid "Command failed"
msgstr ""
msgstr "Команда завершилась з помилкою"
#: src/apprt/gtk/Window.zig:216
msgid "Main Menu"
@@ -301,7 +300,7 @@ msgstr "Переглянути відкриті вкладки"
#: src/apprt/gtk/Window.zig:266
msgid "New Split"
msgstr ""
msgstr "Нова панель"
#: src/apprt/gtk/Window.zig:329
msgid ""
@@ -311,7 +310,7 @@ msgstr ""
#: src/apprt/gtk/Window.zig:775
msgid "Reloaded the configuration"
msgstr "Конфігурацію перезавантажено"
msgstr "Налаштування перезавантажено"
#: src/apprt/gtk/Window.zig:1019
msgid "Ghostty Developers"

View File

@@ -247,6 +247,7 @@ const DerivedConfig = struct {
clipboard_paste_protection: bool,
clipboard_paste_bracketed_safe: bool,
copy_on_select: configpkg.CopyOnSelect,
right_click_action: configpkg.RightClickAction,
confirm_close_surface: configpkg.ConfirmCloseSurface,
cursor_click_to_move: bool,
desktop_notifications: bool,
@@ -257,6 +258,7 @@ const DerivedConfig = struct {
mouse_shift_capture: configpkg.MouseShiftCapture,
macos_non_native_fullscreen: configpkg.NonNativeFullscreen,
macos_option_as_alt: ?configpkg.OptionAsAlt,
selection_clear_on_copy: bool,
selection_clear_on_typing: bool,
vt_kam_allowed: bool,
wait_after_command: bool,
@@ -271,6 +273,7 @@ const DerivedConfig = struct {
title_report: bool,
links: []Link,
link_previews: configpkg.LinkPreviews,
scroll_to_bottom: configpkg.Config.ScrollToBottom,
const Link = struct {
regex: oni.Regex,
@@ -314,6 +317,7 @@ const DerivedConfig = struct {
.clipboard_paste_protection = config.@"clipboard-paste-protection",
.clipboard_paste_bracketed_safe = config.@"clipboard-paste-bracketed-safe",
.copy_on_select = config.@"copy-on-select",
.right_click_action = config.@"right-click-action",
.confirm_close_surface = config.@"confirm-close-surface",
.cursor_click_to_move = config.@"cursor-click-to-move",
.desktop_notifications = config.@"desktop-notifications",
@@ -324,6 +328,7 @@ const DerivedConfig = struct {
.mouse_shift_capture = config.@"mouse-shift-capture",
.macos_non_native_fullscreen = config.@"macos-non-native-fullscreen",
.macos_option_as_alt = config.@"macos-option-as-alt",
.selection_clear_on_copy = config.@"selection-clear-on-copy",
.selection_clear_on_typing = config.@"selection-clear-on-typing",
.vt_kam_allowed = config.@"vt-kam-allowed",
.wait_after_command = config.@"wait-after-command",
@@ -338,6 +343,7 @@ const DerivedConfig = struct {
.title_report = config.@"title-report",
.links = links,
.link_previews = config.@"link-previews",
.scroll_to_bottom = config.@"scroll-to-bottom",
// Assignments happen sequentially so we have to do this last
// so that the memory is captured from allocs above.
@@ -1529,11 +1535,6 @@ pub const Text = struct {
/// The viewport information about this text, if it is visible in
/// the viewport.
///
/// NOTE(mitchellh): This will only be non-null currently if the entirety
/// of the selection is contained within the viewport. We don't have a
/// use case currently for partial bounds but we should support this
/// eventually.
viewport: ?Viewport = null,
pub const Viewport = struct {
@@ -1544,6 +1545,13 @@ pub const Text = struct {
/// The linear offset of the start of the selection and the length.
/// This is "linear" in the sense that it is the offset in the
/// flattened viewport as a single array of text.
///
/// Note: these values are currently wrong if there is a partially
/// visible selection in the viewport (i.e. the top-left or
/// bottom-right of the selection is outside the viewport). But the
/// apprt usecase we have right now doesn't require these to be
/// correct so... let's fix this later. The wrong values will always
/// be within the text bounds so we aren't risking an overflow.
offset_start: u32,
offset_len: u32,
};
@@ -1585,17 +1593,57 @@ pub fn dumpTextLocked(
// Calculate our viewport info if we can.
const vp: ?Text.Viewport = viewport: {
// If our tl or br is not in the viewport then we don't
// have a viewport. One day we should extend this to support
// partial selections that are in the viewport.
const tl_pt = self.io.terminal.screen.pages.pointFromPin(
// If our bottom right pin is before the viewport, then we can't
// possibly have this text be within the viewport.
const vp_tl_pin = self.io.terminal.screen.pages.getTopLeft(.viewport);
const br_pin = sel.bottomRight(&self.io.terminal.screen);
if (br_pin.before(vp_tl_pin)) break :viewport null;
// If our top-left pin is after the viewport, then we can't possibly
// have this text be within the viewport.
const vp_br_pin = self.io.terminal.screen.pages.getBottomRight(.viewport) orelse {
// I don't think this is possible but I don't want to crash on
// that assertion so let's just break out...
log.warn("viewport bottom-right pin not found, bug?", .{});
break :viewport null;
};
const tl_pin = sel.topLeft(&self.io.terminal.screen);
if (vp_br_pin.before(tl_pin)) break :viewport null;
// We established that our top-left somewhere before the viewport
// bottom-right and that our bottom-right is somewhere after
// the top-left. This means that at least some portion of our
// selection is within the viewport.
// Our top-left point. If it doesn't exist in the viewport it must
// be before and we can return (0,0).
const tl_pt: terminal.Point = self.io.terminal.screen.pages.pointFromPin(
.viewport,
sel.topLeft(&self.io.terminal.screen),
) orelse break :viewport null;
tl_pin,
) orelse tl: {
if (comptime std.debug.runtime_safety) {
assert(tl_pin.before(vp_tl_pin));
}
break :tl .{ .viewport = .{} };
};
// Our bottom-right point. If it doesn't exist in the viewport
// it must be the bottom-right of the viewport.
const br_pt = self.io.terminal.screen.pages.pointFromPin(
.viewport,
sel.bottomRight(&self.io.terminal.screen),
) orelse break :viewport null;
br_pin,
) orelse br: {
if (comptime std.debug.runtime_safety) {
assert(vp_br_pin.before(br_pin));
}
break :br self.io.terminal.screen.pages.pointFromPin(
.viewport,
vp_br_pin,
).?;
};
const tl_coord = tl_pt.coord();
const br_coord = br_pt.coord();
@@ -1666,73 +1714,6 @@ pub fn selectionString(self: *Surface, alloc: Allocator) !?[:0]const u8 {
});
}
/// Return the apprt selection metadata used by apprt's for implementing
/// things like contextual information on right click and so on.
///
/// This only returns non-null if the selection is fully contained within
/// the viewport. The use case for this function at the time of authoring
/// it is for apprt's to implement right-click contextual menus and
/// those only make sense for selections fully contained within the
/// viewport. We don't handle the case where you right click a word-wrapped
/// word at the end of the viewport yet.
pub fn selectionInfo(self: *const Surface) ?apprt.Selection {
self.renderer_state.mutex.lock();
defer self.renderer_state.mutex.unlock();
const sel = self.io.terminal.screen.selection orelse return null;
// Get the TL/BR pins for the selection and convert to viewport.
const tl = sel.topLeft(&self.io.terminal.screen);
const br = sel.bottomRight(&self.io.terminal.screen);
const tl_pt = self.io.terminal.screen.pages.pointFromPin(.viewport, tl) orelse return null;
const br_pt = self.io.terminal.screen.pages.pointFromPin(.viewport, br) orelse return null;
const tl_coord = tl_pt.coord();
const br_coord = br_pt.coord();
// Utilize viewport sizing to convert to offsets
const start = tl_coord.y * self.io.terminal.screen.pages.cols + tl_coord.x;
const end = br_coord.y * self.io.terminal.screen.pages.cols + br_coord.x;
// Our sizes are all scaled so we need to send the unscaled values back.
const content_scale = self.rt_surface.getContentScale() catch .{ .x = 1, .y = 1 };
const x: f64 = x: {
// Simple x * cell width gives the left
var x: f64 = @floatFromInt(tl_coord.x * self.size.cell.width);
// Add padding
x += @floatFromInt(self.size.padding.left);
// Scale
x /= content_scale.x;
break :x x;
};
const y: f64 = y: {
// Simple y * cell height gives the top
var y: f64 = @floatFromInt(tl_coord.y * self.size.cell.height);
// We want the text baseline
y += @floatFromInt(self.size.cell.height);
y -= @floatFromInt(self.font_metrics.cell_baseline);
// Add padding
y += @floatFromInt(self.size.padding.top);
// Scale
y /= content_scale.y;
break :y y;
};
return .{
.tl_x_px = x,
.tl_y_px = y,
.offset_start = start,
.offset_len = end - start,
};
}
/// Returns the pwd of the terminal, if any. This is always copied because
/// the pwd can change at any point from termio. If we are calling from the IO
/// thread you should just check the terminal directly.
@@ -1751,6 +1732,7 @@ pub fn pwd(
pub fn imePoint(self: *const Surface) apprt.IMEPos {
self.renderer_state.mutex.lock();
const cursor = self.renderer_state.terminal.screen.cursor;
const preedit_width: usize = if (self.renderer_state.preedit) |preedit| preedit.width() else 0;
self.renderer_state.mutex.unlock();
// TODO: need to handle when scrolling and the cursor is not
@@ -1785,7 +1767,38 @@ pub fn imePoint(self: *const Surface) apprt.IMEPos {
break :y y;
};
return .{ .x = x, .y = y };
// Our height for now is always just the cell height because our preedit
// rendering only renders in a single line.
const height: f64 = height: {
var height: f64 = @floatFromInt(self.size.cell.height);
height /= content_scale.y;
break :height height;
};
const width: f64 = width: {
var width: f64 = @floatFromInt(preedit_width * self.size.cell.width);
// Our max width is the remaining screen width after the cursor.
// We don't have to deal with wrapping because the preedit doesn't
// wrap right now.
const screen_width: f64 = @floatFromInt(self.size.terminal().width);
const x_offset: f64 = @floatFromInt((cursor.x + 1) * self.size.cell.width);
const max = screen_width - x_offset;
width = @min(width, max);
// Note: we don't apply content scale here because it looks like
// for some reason in macOS its already scaled. I'm not sure why
// that is so I'm going to just leave this comment here so its known
// that I left this out on purpose pending more investigation.
break :width width;
};
return .{
.x = x,
.y = y,
.width = width,
.height = height,
};
}
fn clipboardWrite(self: *const Surface, data: []const u8, loc: apprt.Clipboard) !void {
@@ -1833,6 +1846,32 @@ fn clipboardWrite(self: *const Surface, data: []const u8, loc: apprt.Clipboard)
};
}
fn copySelectionToClipboards(
self: *Surface,
sel: terminal.Selection,
clipboards: []const apprt.Clipboard,
) void {
const buf = self.io.terminal.screen.selectionString(self.alloc, .{
.sel = sel,
.trim = self.config.clipboard_trim_trailing_spaces,
}) catch |err| {
log.err("error reading selection string err={}", .{err});
return;
};
defer self.alloc.free(buf);
for (clipboards) |clipboard| self.rt_surface.setClipboardString(
buf,
clipboard,
false,
) catch |err| {
log.err(
"error setting clipboard string clipboard={} err={}",
.{ clipboard, err },
);
};
}
/// Set the selection contents.
///
/// This must be called with the renderer mutex held.
@@ -1850,33 +1889,12 @@ fn setSelection(self: *Surface, sel_: ?terminal.Selection) !void {
const sel = sel_ orelse return;
if (prev_) |prev| if (sel.eql(prev)) return;
const buf = self.io.terminal.screen.selectionString(self.alloc, .{
.sel = sel,
.trim = self.config.clipboard_trim_trailing_spaces,
}) catch |err| {
log.err("error reading selection string err={}", .{err});
return;
};
defer self.alloc.free(buf);
// Set the clipboard. This is not super DRY but it is clear what
// we're doing for each setting without being clever.
switch (self.config.copy_on_select) {
.false => unreachable, // handled above with an early exit
// Both standard and selection clipboards are set.
.clipboard => {
const clipboards: []const apprt.Clipboard = &.{ .standard, .selection };
for (clipboards) |clipboard| self.rt_surface.setClipboardString(
buf,
clipboard,
false,
) catch |err| {
log.err(
"error setting clipboard string clipboard={} err={}",
.{ clipboard, err },
);
};
self.copySelectionToClipboards(sel, &.{ .standard, .selection });
},
// The selection clipboard is set if supported, otherwise the standard.
@@ -1885,17 +1903,7 @@ fn setSelection(self: *Surface, sel_: ?terminal.Selection) !void {
.selection
else
.standard;
self.rt_surface.setClipboardString(
buf,
clipboard,
false,
) catch |err| {
log.err(
"error setting clipboard string clipboard={} err={}",
.{ clipboard, err },
);
};
self.copySelectionToClipboards(sel, &.{clipboard});
},
}
}
@@ -2308,7 +2316,8 @@ pub fn keyCallback(
try self.setSelection(null);
}
try self.io.terminal.scrollViewport(.{ .bottom = {} });
if (self.config.scroll_to_bottom.keystroke) try self.io.terminal.scrollViewport(.bottom);
try self.queueRender();
}
@@ -2794,8 +2803,21 @@ pub fn scrollCallback(
// that a wheel tick of 1 results in single scroll event.
const yoff_adjusted: f64 = if (scroll_mods.precision)
yoff
else
yoff * cell_size * self.config.mouse_scroll_multiplier;
else yoff_adjusted: {
// Round out the yoff to an absolute minimum of 1. macos tries to
// simulate precision scrolling with non precision events by
// ramping up the magnitude of the offsets as it detects faster
// scrolling. Single click (very slow) scrolls are reported with a
// magnitude of 0.1 which would normally require a few clicks
// before we register an actual scroll event (depending on cell
// height and the mouse_scroll_multiplier setting).
const yoff_max: f64 = if (yoff > 0)
@max(yoff, 1)
else
@min(yoff, -1);
break :yoff_adjusted yoff_max * cell_size * self.config.mouse_scroll_multiplier;
};
// Add our previously saved pending amount to the offset to get the
// new offset value. The signs of the pending and yoff should match
@@ -3582,18 +3604,63 @@ pub fn mouseButtonCallback(
break :pin pin;
};
// If we already have a selection and the selection contains
// where we clicked then we don't want to modify the selection.
if (self.io.terminal.screen.selection) |prev_sel| {
if (prev_sel.contains(screen, pin)) break :sel;
switch (self.config.right_click_action) {
.ignore => {},
.@"context-menu" => {
// If we already have a selection and the selection contains
// where we clicked then we don't want to modify the selection.
if (self.io.terminal.screen.selection) |prev_sel| {
if (prev_sel.contains(screen, pin)) break :sel;
// The selection doesn't contain our pin, so we create a new
// word selection where we clicked.
// The selection doesn't contain our pin, so we create a new
// word selection where we clicked.
}
const sel = screen.selectWord(pin) orelse break :sel;
try self.setSelection(sel);
try self.queueRender();
// Don't consume so that we show the context menu in apprt.
return false;
},
.copy => {
if (self.io.terminal.screen.selection) |sel| {
self.copySelectionToClipboards(sel, &.{.standard});
}
try self.setSelection(null);
try self.queueRender();
},
.@"copy-or-paste" => if (self.io.terminal.screen.selection) |sel| {
self.copySelectionToClipboards(sel, &.{.standard});
try self.setSelection(null);
try self.queueRender();
} else {
// Pasting can trigger a lock grab in complete clipboard
// request so we need to unlock.
self.renderer_state.mutex.unlock();
defer self.renderer_state.mutex.lock();
try self.startClipboardRequest(.standard, .paste);
// We don't need to clear selection because we didn't have
// one to begin with.
},
.paste => {
// Before we yield the lock, clear our selection if we have
// one.
try self.setSelection(null);
try self.queueRender();
// Pasting can trigger a lock grab in complete clipboard
// request so we need to unlock.
self.renderer_state.mutex.unlock();
defer self.renderer_state.mutex.lock();
try self.startClipboardRequest(.standard, .paste);
},
}
const sel = screen.selectWord(pin) orelse break :sel;
try self.setSelection(sel);
try self.queueRender();
// Consume the event such that the context menu is not displayed.
return true;
}
return false;
@@ -4479,6 +4546,17 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
return true;
};
// Clear the selection if configured to do so.
if (self.config.selection_clear_on_copy) {
if (self.setSelection(null)) {
self.queueRender() catch |err| {
log.warn("failed to queue render after clear selection err={}", .{err});
};
} else |err| {
log.warn("failed to clear selection after copy err={}", .{err});
}
}
return true;
}
@@ -4491,19 +4569,32 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
const pos = try self.rt_surface.getCursorPos();
if (try self.linkAtPos(pos)) |link_info| {
// Get the URL text from selection
const url_text = (self.io.terminal.screen.selectionString(self.alloc, .{
.sel = link_info[1],
.trim = self.config.clipboard_trim_trailing_spaces,
})) catch |err| {
log.err("error reading url string err={}", .{err});
return false;
const url_text = switch (link_info[0]) {
.open => url_text: {
// For regex links, get the text from selection
break :url_text (self.io.terminal.screen.selectionString(self.alloc, .{
.sel = link_info[1],
.trim = self.config.clipboard_trim_trailing_spaces,
})) catch |err| {
log.err("error reading url string err={}", .{err});
return false;
};
},
._open_osc8 => url_text: {
// For OSC8 links, get the URI directly from hyperlink data
const uri = self.osc8URI(link_info[1].start()) orelse {
log.warn("failed to get URI for OSC8 hyperlink", .{});
return false;
};
break :url_text try self.alloc.dupeZ(u8, uri);
},
};
defer self.alloc.free(url_text);
self.rt_surface.setClipboardString(url_text, .standard, false) catch |err| {
log.err("error copying url to clipboard err={}", .{err});
return true;
return false;
};
return true;
@@ -4671,10 +4762,13 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
{},
),
.close_tab => return try self.rt_app.performAction(
.close_tab => |v| return try self.rt_app.performAction(
.{ .surface = self },
.close_tab,
{},
switch (v) {
.this => .this,
.other => .other,
},
),
inline .previous_tab,
@@ -4804,6 +4898,12 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
{},
),
.show_on_screen_keyboard => return try self.rt_app.performAction(
.{ .surface = self },
.show_on_screen_keyboard,
{},
),
.select_all => {
const sel = self.io.terminal.screen.selectAll();
if (sel) |s| {

View File

@@ -60,21 +60,25 @@ pub const Runtime = enum {
/// This is only useful if you're only interested in the lib only (macOS).
none,
/// GTK-backed. Rich windowed application. GTK is dynamically linked.
gtk,
/// GTK4. The "-ng" variant is a rewrite of the GTK backend using
/// GTK-native technologies such as full GObject classes, Blueprint
/// files, etc.
/// GTK4. Rich windowed application. This uses a full GObject-based
/// approach to building the application.
@"gtk-ng",
pub fn default(target: std.Target) Runtime {
// The Linux default is GTK because it is full featured.
if (target.os.tag == .linux) return .gtk;
/// GTK-backed. Rich windowed application. GTK is dynamically linked.
/// WARNING: Deprecated. This will be removed very soon. All bug fixes
/// and features should go into the gtk-ng backend.
gtk,
// Otherwise, we do NONE so we don't create an exe and we
// create libghostty.
return .none;
pub fn default(target: std.Target) Runtime {
return switch (target.os.tag) {
// The Linux and FreeBSD default is GTK because it is a full
// featured application.
.linux, .freebsd => .@"gtk-ng",
// Otherwise, we do NONE so we don't create an exe and we create
// libghostty. On macOS, Xcode is used to build the app that links
// to libghostty.
else => .none,
};
}
};

View File

@@ -1,4 +1,5 @@
const std = @import("std");
const build_config = @import("../build_config.zig");
const assert = std.debug.assert;
const apprt = @import("../apprt.zig");
const configpkg = @import("../config.zig");
@@ -82,8 +83,9 @@ pub const Action = union(Key) {
/// the tab should be opened in a new window.
new_tab,
/// Closes the tab belonging to the currently focused split.
close_tab,
/// Closes the tab belonging to the currently focused split, or all other
/// tabs, depending on the mode.
close_tab: CloseTabMode,
/// Create a new split. The value determines the location of the split
/// relative to the target.
@@ -290,6 +292,9 @@ pub const Action = union(Key) {
/// Show a native GUI notification about the progress of some TUI operation.
progress_report: terminal.osc.Command.ProgressReport,
/// Show the on-screen keyboard.
show_on_screen_keyboard,
/// Sync with: ghostty_action_tag_e
pub const Key = enum(c_int) {
quit,
@@ -344,6 +349,7 @@ pub const Action = union(Key) {
open_url,
show_child_exited,
progress_report,
show_on_screen_keyboard,
};
/// Sync with: ghostty_action_u
@@ -533,6 +539,16 @@ pub const SizeLimit = extern struct {
pub const InitialSize = extern struct {
width: u32,
height: u32,
/// Make this a valid gobject if we're in a GTK environment.
pub const getGObjectType = switch (build_config.app_runtime) {
.gtk, .@"gtk-ng" => @import("gobject").ext.defineBoxed(
InitialSize,
.{ .name = "GhosttyApprtInitialSize" },
),
.none => void,
};
};
pub const CellSize = extern struct {
@@ -686,3 +702,11 @@ pub const OpenUrl = struct {
};
}
};
/// sync with ghostty_action_close_tab_mode_e in ghostty.h
pub const CloseTabMode = enum(c_int) {
/// Close the current tab.
this,
/// Close all other tabs.
other,
};

View File

@@ -447,6 +447,9 @@ pub const Surface = struct {
/// Input to send to the command after it is started.
initial_input: ?[*:0]const u8 = null,
/// Wait after the command exits
wait_after_command: bool = false,
};
pub fn init(self: *Surface, app: *App, opts: Options) !void {
@@ -540,6 +543,11 @@ pub const Surface = struct {
);
}
// Wait after command
if (opts.wait_after_command) {
config.@"wait-after-command" = true;
}
// Initialize our surface right away. We're given a view that is
// ready to use.
try self.core_surface.init(
@@ -1814,10 +1822,18 @@ pub const CAPI = struct {
surface.mousePressureCallback(stage, pressure);
}
export fn ghostty_surface_ime_point(surface: *Surface, x: *f64, y: *f64) void {
export fn ghostty_surface_ime_point(
surface: *Surface,
x: *f64,
y: *f64,
width: *f64,
height: *f64,
) void {
const pos = surface.core_surface.imePoint();
x.* = pos.x;
y.* = pos.y;
width.* = pos.width;
height.* = pos.height;
}
/// Request that the surface become closed. This will go through the

View File

@@ -11,4 +11,5 @@ pub const WeakRef = @import("gtk-ng/weak_ref.zig").WeakRef;
test {
@import("std").testing.refAllDecls(@This());
_ = @import("gtk-ng/ext.zig");
}

View File

@@ -3,6 +3,7 @@
const App = @This();
const std = @import("std");
const builtin = @import("builtin");
const Allocator = std.mem.Allocator;
const adw = @import("adw");
const gio = @import("gio");
@@ -16,6 +17,7 @@ const Application = @import("class/application.zig").Application;
const Surface = @import("Surface.zig");
const gtk_version = @import("gtk_version.zig");
const adw_version = @import("adw_version.zig");
const ipcNewWindow = @import("ipc/new_window.zig").newWindow;
const log = std.log.scoped(.gtk);
@@ -24,6 +26,18 @@ const log = std.log.scoped(.gtk);
/// because GTK's `GLArea` does not support drawing from a different thread.
pub const must_draw_from_app_thread = true;
/// GTK application ID
pub const application_id = switch (builtin.mode) {
.Debug, .ReleaseSafe => "com.mitchellh.ghostty-debug",
.ReleaseFast, .ReleaseSmall => "com.mitchellh.ghostty",
};
/// GTK object path
pub const object_path = switch (builtin.mode) {
.Debug, .ReleaseSafe => "/com/mitchellh/ghostty_debug",
.ReleaseFast, .ReleaseSmall => "/com/mitchellh/ghostty",
};
/// The GObject Application instance
app: *Application,
@@ -67,20 +81,24 @@ pub fn performAction(
return try self.app.performAction(target, action, value);
}
/// Send the given IPC to a running Ghostty. Returns `true` if the action was
/// able to be performed, `false` otherwise.
///
/// Note that this is a static function. Since this is called from a CLI app (or
/// some other process that is not Ghostty) there is no full-featured apprt App
/// to use.
pub fn performIpc(
alloc: Allocator,
target: apprt.ipc.Target,
comptime action: apprt.ipc.Action.Key,
value: apprt.ipc.Action.Value(action),
) !bool {
_ = alloc;
_ = target;
_ = value;
return false;
switch (action) {
.new_window => return try ipcNewWindow(alloc, target, value),
}
}
/// Redraw the inspector for the given surface.
pub fn redrawInspector(self: *App, surface: *Surface) void {
_ = self;
_ = surface;
pub fn redrawInspector(_: *App, surface: *Surface) void {
surface.redrawInspector();
}

View File

@@ -32,25 +32,18 @@ pub fn rtApp(self: *Self) *ApprtApp {
}
pub fn close(self: *Self, process_active: bool) void {
self.surface.close(process_active);
_ = process_active;
self.surface.close();
}
pub fn cgroup(self: *Self) ?[]const u8 {
return self.surface.cgroupPath();
}
pub fn setPwd(self: *Self, pwd: [:0]const u8) void {
return self.surface.setPwd(pwd);
}
pub fn getTitle(self: *Self) ?[:0]const u8 {
return self.surface.getTitle();
}
pub fn setTitle(self: *Self, title: [:0]const u8) void {
return self.surface.setTitle(title);
}
pub fn getContentScale(self: *const Self) !apprt.ContentScale {
return self.surface.getContentScale();
}
@@ -103,3 +96,8 @@ pub fn setClipboardString(
pub fn defaultTermioEnv(self: *Self) !std.process.EnvMap {
return try self.surface.defaultTermioEnv();
}
/// Redraw the inspector for our surface.
pub fn redrawInspector(self: *Self) void {
self.surface.redrawInspector();
}

View File

@@ -37,17 +37,28 @@ pub const blueprints: []const Blueprint = &.{
.{ .major = 1, .minor = 4, .name = "clipboard-confirmation-dialog" },
.{ .major = 1, .minor = 2, .name = "close-confirmation-dialog" },
.{ .major = 1, .minor = 2, .name = "config-errors-dialog" },
.{ .major = 1, .minor = 2, .name = "debug-warning" },
.{ .major = 1, .minor = 3, .name = "debug-warning" },
.{ .major = 1, .minor = 5, .name = "imgui-widget" },
.{ .major = 1, .minor = 5, .name = "inspector-widget" },
.{ .major = 1, .minor = 5, .name = "inspector-window" },
.{ .major = 1, .minor = 2, .name = "resize-overlay" },
.{ .major = 1, .minor = 5, .name = "split-tree" },
.{ .major = 1, .minor = 5, .name = "split-tree-split" },
.{ .major = 1, .minor = 2, .name = "surface" },
.{ .major = 1, .minor = 5, .name = "surface-title-dialog" },
.{ .major = 1, .minor = 3, .name = "surface-child-exited" },
.{ .major = 1, .minor = 5, .name = "tab" },
.{ .major = 1, .minor = 5, .name = "window" },
.{ .major = 1, .minor = 5, .name = "command-palette" },
};
/// CSS files in css_path
pub const css = [_][]const u8{
"style.css",
// "style-dark.css",
// "style-hc.css",
// "style-hc-dark.css",
"style-dark.css",
"style-hc.css",
"style-hc-dark.css",
};
pub const Blueprint = struct {
@@ -63,8 +74,8 @@ pub const file_inputs = deps: {
var deps: [total][]const u8 = undefined;
var index: usize = 0;
for (icon_sizes) |size| {
deps[index] = std.fmt.comptimePrint("images/icons/icon_{d}.png", .{size});
deps[index + 1] = std.fmt.comptimePrint("images/icons/icon_{d}@2x.png", .{size});
deps[index] = std.fmt.comptimePrint("images/gnome/{d}.png", .{size});
deps[index + 1] = std.fmt.comptimePrint("images/gnome/{d}.png", .{size * 2});
index += 2;
}
for (blueprints) |bp| {
@@ -162,7 +173,7 @@ fn genIcons(writer: anytype) !void {
// 1x
{
const alias = std.fmt.comptimePrint("{d}x{d}", .{ size, size });
const source = std.fmt.comptimePrint("images/icons/icon_{d}.png", .{size});
const source = std.fmt.comptimePrint("images/gnome/{d}.png", .{size});
try cwd.access(source, .{});
try writer.print(
\\ <file alias="{s}/apps/{s}.png">{s}</file>
@@ -175,7 +186,7 @@ fn genIcons(writer: anytype) !void {
// 2x
{
const alias = std.fmt.comptimePrint("{d}x{d}@2", .{ size, size });
const source = std.fmt.comptimePrint("images/icons/icon_{d}@2x.png", .{size});
const source = std.fmt.comptimePrint("images/gnome/{d}.png", .{size * 2});
try cwd.access(source, .{});
try writer.print(
\\ <file alias="{s}/apps/{s}.png">{s}</file>

View File

@@ -1,10 +1,12 @@
//! This files contains all the GObject classes for the GTK apprt
//! along with helpers to work with them.
const std = @import("std");
const glib = @import("glib");
const gobject = @import("gobject");
const gtk = @import("gtk");
const ext = @import("ext.zig");
pub const Application = @import("class/application.zig").Application;
pub const Window = @import("class/window.zig").Window;
pub const Config = @import("class/config.zig").Config;
@@ -29,6 +31,12 @@ pub fn Common(
return @ptrCast(@alignCast(gobject.Object.ref(self.as(gobject.Object))));
}
/// If the reference count is 1 and the object is floating, clear the
/// floating attribute. Otherwise, increase the reference count by 1.
pub fn refSink(self: *Self) *Self {
return @ptrCast(@alignCast(gobject.Object.refSink(self.as(gobject.Object))));
}
/// Decrease the reference count of the object.
pub fn unref(self: *Self) void {
gobject.Object.unref(self.as(gobject.Object));
@@ -46,6 +54,209 @@ pub fn Common(
}
}).private else {};
/// Get the class for the object.
///
/// This _seems_ ugly and unsafe but this is how GObject
/// works under the hood. From the [GObject Type System
/// Concepts](https://docs.gtk.org/gobject/concepts.html) documentation:
///
/// Every object must define two structures: its class structure
/// and its instance structure. All class structures must contain
/// as first member a GTypeClass structure. All instance structures
/// must contain as first member a GTypeInstance structure.
/// …
/// These constraints allow the type system to make sure that
/// every object instance (identified by a pointer to the objects
/// instance structure) contains in its first bytes a pointer to the
/// objects class structure.
/// …
/// The C standard mandates that the first field of a C structure is
/// stored starting in the first byte of the buffer used to hold the
/// structures fields in memory. This means that the first field of
/// an instance of an object B is As first field which in turn is
/// GTypeInstances first field which in turn is g_class, a pointer
/// to Bs class structure.
///
/// This means that to access the class structure for an object you cast it
/// to `*gobject.TypeInstance` and then access the `f_g_class` field.
///
/// https://gitlab.gnome.org/GNOME/glib/-/blob/2c08654b62d52a31c4e4d13d7d85e12b989e72be/gobject/gtype.h#L555-571
/// https://gitlab.gnome.org/GNOME/glib/-/blob/2c08654b62d52a31c4e4d13d7d85e12b989e72be/gobject/gtype.h#L2673
///
pub fn getClass(self: *Self) ?*Self.Class {
const type_instance: *gobject.TypeInstance = @ptrCast(self);
return @ptrCast(type_instance.f_g_class orelse return null);
}
/// Define a virtual method. The `Self.Class` type must have a field
/// named `name` which is a function pointer in the following form:
///
/// ?*const fn (*Self) callconv(.c) void
///
/// The virtual method may take additional parameters and specify
/// a non-void return type. The parameters and return type must be
/// valid for the C calling convention.
pub fn defineVirtualMethod(
comptime name: [:0]const u8,
) type {
return struct {
pub fn call(
class: anytype,
object: *ClassInstance(@TypeOf(class)),
params: anytype,
) (fn_info.return_type orelse void) {
const func = @field(
gobject.ext.as(Self.Class, class),
name,
).?;
@call(.auto, func, .{
gobject.ext.as(Self, object),
} ++ params);
}
pub fn implement(
class: anytype,
implementation: *const ImplementFunc(@TypeOf(class)),
) void {
@field(gobject.ext.as(
Self.Class,
class,
), name) = @ptrCast(implementation);
}
/// The type info of the virtual method.
const fn_info = fn_info: {
// This is broken down like this so its slightly more
// readable. We expect a field named "name" on the Class
// with the rough type of `?*const fn` and we need the
// function info.
const Field = @FieldType(Self.Class, name);
const opt = @typeInfo(Field).optional;
const ptr = @typeInfo(opt.child).pointer;
break :fn_info @typeInfo(ptr.child).@"fn";
};
/// The instance type for a class.
fn ClassInstance(comptime T: type) type {
return @typeInfo(T).pointer.child.Instance;
}
/// The function type for implementations. This is the same type
/// as the virtual method but the self parameter points to the
/// target instead of the original class.
fn ImplementFunc(comptime T: type) type {
var params: [fn_info.params.len]std.builtin.Type.Fn.Param = undefined;
@memcpy(&params, fn_info.params);
params[0].type = *ClassInstance(T);
return @Type(.{ .@"fn" = .{
.calling_convention = fn_info.calling_convention,
.is_generic = fn_info.is_generic,
.is_var_args = fn_info.is_var_args,
.return_type = fn_info.return_type,
.params = &params,
} });
}
};
}
/// A helper that creates a property that reads and writes a
/// private field with only shallow copies. This is good for primitives
/// such as bools, numbers, etc.
pub fn privateShallowFieldAccessor(
comptime name: []const u8,
) gobject.ext.Accessor(
Self,
@FieldType(Private.?, name),
) {
return gobject.ext.privateFieldAccessor(
Self,
Private.?,
&Private.?.offset,
name,
);
}
/// A helper that can be used to create a property that reads and
/// writes a private boxed gobject field type.
///
/// Reading the property will result in allocating a pointer and
/// setting it will free the previous pointer.
///
/// The object class (Self) must still free the private field
/// in finalize!
pub fn privateBoxedFieldAccessor(
comptime name: []const u8,
) gobject.ext.Accessor(
Self,
@FieldType(Private.?, name),
) {
return .{
.getter = &struct {
fn get(self: *Self, value: *gobject.Value) void {
gobject.ext.Value.set(
value,
@field(private(self), name),
);
}
}.get,
.setter = &struct {
fn set(self: *Self, value: *const gobject.Value) void {
const priv = private(self);
if (@field(priv, name)) |v| {
ext.boxedFree(
@typeInfo(@TypeOf(v)).pointer.child,
v,
);
}
const T = @TypeOf(@field(priv, name));
@field(
priv,
name,
) = gobject.ext.Value.dup(value, T);
}
}.set,
};
}
/// A helper that can be used to create a property that reads and
/// writes a private field gobject field type (reference counted).
///
/// Reading the property will result in taking a reference to the
/// value and writing the property will unref the previous value.
///
/// The object class (Self) must still free the private field
/// in finalize!
pub fn privateObjFieldAccessor(
comptime name: []const u8,
) gobject.ext.Accessor(
Self,
@FieldType(Private.?, name),
) {
return .{
.getter = &struct {
fn get(self: *Self, value: *gobject.Value) void {
gobject.ext.Value.set(
value,
@field(private(self), name),
);
}
}.get,
.setter = &struct {
fn set(self: *Self, value: *const gobject.Value) void {
const priv = private(self);
if (@field(priv, name)) |v| v.unref();
const T = @TypeOf(@field(priv, name));
@field(
priv,
name,
) = gobject.ext.Value.dup(value, T);
}
}.set,
};
}
/// A helper that can be used to create a property that reads and
/// writes a private `?[:0]const u8` field type.
///
@@ -114,6 +325,39 @@ pub fn Common(
);
}
}).bindTemplateChildPrivate else {};
/// Bind a function pointer to a template callback symbol.
pub fn bindTemplateCallback(
class: *Self.Class,
comptime name: [:0]const u8,
comptime func: anytype,
) void {
{
const ptr_ti = @typeInfo(@TypeOf(func));
if (ptr_ti != .pointer) {
@compileError("bound function must be a pointer type");
}
if (ptr_ti.pointer.size != .one) {
@compileError("bound function must be a pointer to a function");
}
const func_ti = @typeInfo(ptr_ti.pointer.child);
if (func_ti != .@"fn") {
@compileError("bound function must be a function pointer");
}
if (func_ti.@"fn".return_type == bool) {
// glib booleans are ints and returning a Zig bool type
// I think uses a byte and causes ABI issues.
@compileError("bound function must return c_int instead of bool");
}
}
gtk.Widget.Class.bindTemplateCallbackFull(
class.as(gtk.Widget.Class),
name,
@ptrCast(func),
);
}
};
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -37,8 +37,6 @@ pub const ClipboardConfirmationDialog = extern struct {
Self,
bool,
.{
.nick = "Can Remember",
.blurb = "Allow remembering the choice.",
.default = false,
.accessor = gobject.ext.privateFieldAccessor(
Self,
@@ -57,14 +55,7 @@ pub const ClipboardConfirmationDialog = extern struct {
Self,
?*apprt.ClipboardRequest,
.{
.nick = "Request",
.blurb = "The clipboard request.",
.accessor = gobject.ext.privateFieldAccessor(
Self,
Private,
&Private.offset,
"request",
),
.accessor = C.privateBoxedFieldAccessor("request"),
},
);
};
@@ -76,14 +67,7 @@ pub const ClipboardConfirmationDialog = extern struct {
Self,
?*gtk.TextBuffer,
.{
.nick = "Clipboard Contents",
.blurb = "The clipboard contents being read/written.",
.accessor = gobject.ext.privateFieldAccessor(
Self,
Private,
&Private.offset,
"clipboard_contents",
),
.accessor = C.privateObjFieldAccessor("clipboard_contents"),
},
);
};
@@ -95,8 +79,6 @@ pub const ClipboardConfirmationDialog = extern struct {
Self,
bool,
.{
.nick = "Blur",
.blurb = "Blur the contents, allowing the user to reveal.",
.default = false,
.accessor = gobject.ext.privateFieldAccessor(
Self,
@@ -160,43 +142,9 @@ pub const ClipboardConfirmationDialog = extern struct {
return gobject.ext.newInstance(Self, .{});
}
fn init(self: *Self, _: *Class) callconv(.C) void {
fn init(self: *Self, _: *Class) callconv(.c) void {
gtk.Widget.initTemplate(self.as(gtk.Widget));
const priv = self.private();
// Signals
_ = gtk.Button.signals.clicked.connect(
priv.reveal_button,
*Self,
revealButtonClicked,
self,
.{},
);
_ = gtk.Button.signals.clicked.connect(
priv.hide_button,
*Self,
hideButtonClicked,
self,
.{},
);
// Some property signals
_ = gobject.Object.signals.notify.connect(
self,
?*anyopaque,
&propBlur,
null,
.{ .detail = "blur" },
);
_ = gobject.Object.signals.notify.connect(
self,
?*anyopaque,
&propRequest,
null,
.{ .detail = "request" },
);
// Trigger initial values
self.propBlur(undefined, null);
self.propRequest(undefined, null);
@@ -283,7 +231,7 @@ pub const ClipboardConfirmationDialog = extern struct {
fn response(
self: *Self,
response_id: [*:0]const u8,
) callconv(.C) void {
) callconv(.c) void {
const remember: bool = if (comptime can_remember) remember: {
const priv = self.private();
break :remember priv.remember_choice.getActive() != 0;
@@ -306,7 +254,7 @@ pub const ClipboardConfirmationDialog = extern struct {
}
}
fn dispose(self: *Self) callconv(.C) void {
fn dispose(self: *Self) callconv(.c) void {
const priv = self.private();
if (priv.clipboard_contents) |v| {
v.unref();
@@ -324,7 +272,7 @@ pub const ClipboardConfirmationDialog = extern struct {
);
}
fn finalize(self: *Self) callconv(.C) void {
fn finalize(self: *Self) callconv(.c) void {
const priv = self.private();
if (priv.request) |v| {
glib.ext.destroy(v);
@@ -348,7 +296,7 @@ pub const ClipboardConfirmationDialog = extern struct {
var parent: *Parent.Class = undefined;
pub const Instance = Self;
fn init(class: *Class) callconv(.C) void {
fn init(class: *Class) callconv(.c) void {
gtk.Widget.Class.setTemplateFromResource(
class.as(gtk.Widget.Class),
if (comptime adw_version.atLeast(1, 4, 0))
@@ -374,6 +322,12 @@ pub const ClipboardConfirmationDialog = extern struct {
class.bindTemplateChildPrivate("remember_choice", .{});
}
// Template Callbacks
class.bindTemplateCallback("reveal_clicked", &revealButtonClicked);
class.bindTemplateCallback("hide_clicked", &hideButtonClicked);
class.bindTemplateCallback("notify_blur", &propBlur);
class.bindTemplateCallback("notify_request", &propRequest);
// Properties
gobject.ext.registerProperties(class, &.{
properties.blur.impl,
@@ -394,5 +348,6 @@ pub const ClipboardConfirmationDialog = extern struct {
pub const as = C.Class.as;
pub const bindTemplateChildPrivate = C.Class.bindTemplateChildPrivate;
pub const bindTemplateCallback = C.Class.bindTemplateCallback;
};
};

View File

@@ -10,7 +10,7 @@ const Common = @import("../class.zig").Common;
const Config = @import("config.zig").Config;
const Dialog = @import("dialog.zig").Dialog;
const log = std.log.scoped(.gtk_ghostty_config_errors_dialog);
const log = std.log.scoped(.gtk_ghostty_close_confirmation_dialog);
pub const CloseConfirmationDialog = extern struct {
const Self = @This();
@@ -32,8 +32,6 @@ pub const CloseConfirmationDialog = extern struct {
Self,
Target,
.{
.nick = "Target",
.blurb = "The target for this close confirmation.",
.default = .app,
.accessor = gobject.ext.privateFieldAccessor(
Self,
@@ -57,6 +55,17 @@ pub const CloseConfirmationDialog = extern struct {
void,
);
};
pub const cancel = struct {
pub const name = "cancel";
pub const connect = impl.connect;
const impl = gobject.ext.defineSignal(
name,
Self,
&.{},
void,
);
};
};
const Private = struct {
@@ -70,18 +79,18 @@ pub const CloseConfirmationDialog = extern struct {
});
}
fn init(self: *Self, _: *Class) callconv(.C) void {
fn init(self: *Self, _: *Class) callconv(.c) void {
gtk.Widget.initTemplate(self.as(gtk.Widget));
}
pub fn present(self: *Self, parent: ?*gtk.Widget) void {
// Setup our title/body text.
const priv = self.private();
self.as(Dialog.Parent).setHeading(priv.target.title());
self.as(Dialog.Parent).setBody(priv.target.body());
}
pub fn present(self: *Self) void {
const priv = self.private();
self.as(Dialog).present(priv.target.dialogParent());
// Show it
self.as(Dialog).present(parent);
}
pub fn close(self: *Self) void {
@@ -91,17 +100,25 @@ pub const CloseConfirmationDialog = extern struct {
fn response(
self: *Self,
response_id: [*:0]const u8,
) callconv(.C) void {
if (std.mem.orderZ(u8, response_id, "close") != .eq) return;
signals.@"close-request".impl.emit(
self,
null,
.{},
null,
);
) callconv(.c) void {
if (std.mem.orderZ(u8, response_id, "close") == .eq) {
signals.@"close-request".impl.emit(
self,
null,
.{},
null,
);
} else {
signals.cancel.impl.emit(
self,
null,
.{},
null,
);
}
}
fn dispose(self: *Self) callconv(.C) void {
fn dispose(self: *Self) callconv(.c) void {
gtk.Widget.disposeTemplate(
self.as(gtk.Widget),
getGObjectType(),
@@ -116,6 +133,7 @@ pub const CloseConfirmationDialog = extern struct {
const C = Common(Self, Private);
pub const as = C.as;
pub const ref = C.ref;
pub const refSink = C.refSink;
pub const unref = C.unref;
const private = C.private;
@@ -124,7 +142,7 @@ pub const CloseConfirmationDialog = extern struct {
var parent: *Parent.Class = undefined;
pub const Instance = Self;
fn init(class: *Class) callconv(.C) void {
fn init(class: *Class) callconv(.c) void {
gobject.ext.ensureType(Dialog);
gtk.Widget.Class.setTemplateFromResource(
class.as(gtk.Widget.Class),
@@ -142,6 +160,7 @@ pub const CloseConfirmationDialog = extern struct {
// Signals
signals.@"close-request".impl.register(.{});
signals.cancel.impl.register(.{});
// Virtual methods
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
@@ -159,28 +178,25 @@ pub const CloseConfirmationDialog = extern struct {
/// together into one struct that is the sole source of truth.
pub const Target = enum(c_int) {
app,
tab,
window,
surface,
pub fn title(self: Target) [*:0]const u8 {
return switch (self) {
.app => i18n._("Quit Ghostty?"),
.tab => i18n._("Close Tab?"),
.window => i18n._("Close Window?"),
.surface => i18n._("Close Split?"),
};
}
pub fn body(self: Target) [*:0]const u8 {
return switch (self) {
.app => i18n._("All terminal sessions will be terminated."),
};
}
pub fn dialogParent(self: Target) ?*gtk.Widget {
return switch (self) {
.app => {
// Find the currently focused window.
const list = gtk.Window.listToplevels();
defer list.free();
const focused = list.findCustom(null, findActiveWindow);
return @ptrCast(@alignCast(focused.f_data));
},
.tab => i18n._("All terminal sessions in this tab will be terminated."),
.window => i18n._("All terminal sessions in this window will be terminated."),
.surface => i18n._("The currently running process in this split will be terminated."),
};
}
@@ -189,12 +205,3 @@ pub const Target = enum(c_int) {
.{ .name = "GhosttyCloseConfirmationDialogTarget" },
);
};
fn findActiveWindow(data: ?*const anyopaque, _: ?*const anyopaque) callconv(.c) c_int {
const window: *gtk.Window = @ptrCast(@alignCast(@constCast(data orelse return -1)));
// Confusingly, `isActive` returns 1 when active,
// but we want to return 0 to indicate equality.
// Abusing integers to be enums and booleans is a terrible idea, C.
return if (window.isActive() != 0) 0 else -1;
}

View File

@@ -0,0 +1,568 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const adw = @import("adw");
const gio = @import("gio");
const gobject = @import("gobject");
const gtk = @import("gtk");
const input = @import("../../../input.zig");
const gresource = @import("../build/gresource.zig");
const key = @import("../key.zig");
const Common = @import("../class.zig").Common;
const Application = @import("application.zig").Application;
const Window = @import("window.zig").Window;
const Config = @import("config.zig").Config;
const log = std.log.scoped(.gtk_ghostty_command_palette);
pub const CommandPalette = extern struct {
const Self = @This();
parent_instance: Parent,
pub const Parent = adw.Bin;
pub const getGObjectType = gobject.ext.defineClass(Self, .{
.name = "GhosttyCommandPalette",
.instanceInit = &init,
.classInit = &Class.init,
.parent_class = &Class.parent,
.private = .{ .Type = Private, .offset = &Private.offset },
});
pub const properties = struct {
pub const config = struct {
pub const name = "config";
const impl = gobject.ext.defineProperty(
name,
Self,
?*Config,
.{
.accessor = C.privateObjFieldAccessor("config"),
},
);
};
};
pub const signals = struct {
/// Emitted when a command from the command palette is activated. The
/// action contains pointers to allocated data so if a receiver of this
/// signal needs to keep the action around it will need to clone the
/// action or there may be use-after-free errors.
pub const trigger = struct {
pub const name = "trigger";
pub const connect = impl.connect;
const impl = gobject.ext.defineSignal(
name,
Self,
&.{*const input.Binding.Action},
void,
);
};
};
const Private = struct {
/// The configuration that this command palette is using.
config: ?*Config = null,
/// The dialog object containing the palette UI.
dialog: *adw.Dialog,
/// The search input text field.
search: *gtk.SearchEntry,
/// The view containing each result row.
view: *gtk.ListView,
/// The model that provides filtered data for the view to display.
model: *gtk.SingleSelection,
/// The list that serves as the data source of the model.
/// This is where all command data is ultimately stored.
source: *gio.ListStore,
pub var offset: c_int = 0;
};
/// Create a new instance of the command palette. The caller will own a
/// reference to the object.
pub fn new() *Self {
const self = gobject.ext.newInstance(Self, .{});
// Sink ourselves so that we aren't floating anymore. We'll unref
// ourselves when the palette is closed or an action is activated.
_ = self.refSink();
// Bump the ref so that the caller has a reference.
return self.ref();
}
//---------------------------------------------------------------
// Virtual Methods
fn init(self: *Self, _: *Class) callconv(.c) void {
gtk.Widget.initTemplate(self.as(gtk.Widget));
// Listen for any changes to our config.
_ = gobject.Object.signals.notify.connect(
self,
?*anyopaque,
propConfig,
null,
.{
.detail = "config",
},
);
}
fn dispose(self: *Self) callconv(.c) void {
const priv = self.private();
priv.source.removeAll();
if (priv.config) |config| {
config.unref();
priv.config = null;
}
gtk.Widget.disposeTemplate(
self.as(gtk.Widget),
getGObjectType(),
);
gobject.Object.virtual_methods.dispose.call(
Class.parent,
self.as(Parent),
);
}
//---------------------------------------------------------------
// Signal Handlers
fn propConfig(self: *CommandPalette, _: *gobject.ParamSpec, _: ?*anyopaque) callconv(.c) void {
const priv = self.private();
const config = priv.config orelse {
log.warn("command palette does not have a config!", .{});
return;
};
const cfg = config.get();
// Clear existing binds
priv.source.removeAll();
for (cfg.@"command-palette-entry".value.items) |command| {
// Filter out actions that are not implemented or don't make sense
// for GTK.
switch (command.action) {
.close_all_windows,
.toggle_secure_input,
.check_for_updates,
.redo,
.undo,
.reset_window_size,
.toggle_window_float_on_top,
=> continue,
else => {},
}
const cmd = Command.new(config, command);
const cmd_ref = cmd.as(gobject.Object);
priv.source.append(cmd_ref);
cmd_ref.unref();
}
}
fn close(self: *CommandPalette) void {
const priv = self.private();
_ = priv.dialog.close();
}
fn dialogClosed(_: *adw.Dialog, self: *CommandPalette) callconv(.c) void {
self.unref();
}
fn searchStopped(_: *gtk.SearchEntry, self: *CommandPalette) callconv(.c) void {
// ESC was pressed - close the palette
self.close();
}
fn searchActivated(_: *gtk.SearchEntry, self: *CommandPalette) callconv(.c) void {
// If Enter is pressed, activate the selected entry
const priv = self.private();
self.activated(priv.model.getSelected());
}
fn rowActivated(_: *gtk.ListView, pos: c_uint, self: *CommandPalette) callconv(.c) void {
self.activated(pos);
}
//---------------------------------------------------------------
/// Show or hide the command palette dialog. If the dialog is shown it will
/// be modal over the given window.
pub fn toggle(self: *CommandPalette, window: *Window) void {
const priv = self.private();
// If the dialog has been shown, close it.
if (priv.dialog.as(gtk.Widget).getRealized() != 0) {
self.close();
return;
}
// Show the dialog
priv.dialog.present(window.as(gtk.Widget));
// Focus on the search bar when opening the dialog
_ = priv.search.as(gtk.Widget).grabFocus();
}
/// Helper function to send a signal containing the action that should be
/// performed.
fn activated(self: *CommandPalette, pos: c_uint) void {
const priv = self.private();
// Use priv.model and not priv.source here to use the list of *visible* results
const object_ = priv.model.as(gio.ListModel).getObject(pos);
defer if (object_) |object| object.unref();
// Close before running the action in order to avoid being replaced by
// another dialog (such as the change title dialog). If that occurs then
// the command palette dialog won't be counted as having closed properly
// and cannot receive focus when reopened.
self.close();
const cmd = gobject.ext.cast(Command, object_ orelse return) orelse return;
const action = cmd.getAction() orelse return;
// Signal that an an action has been selected. Signals are synchronous
// so we shouldn't need to worry about cloning the action.
signals.trigger.impl.emit(
self,
null,
.{&action},
null,
);
}
const C = Common(Self, Private);
pub const as = C.as;
pub const ref = C.ref;
pub const refSink = C.refSink;
pub const unref = C.unref;
const private = C.private;
pub const Class = extern struct {
parent_class: Parent.Class,
var parent: *Parent.Class = undefined;
pub const Instance = Self;
fn init(class: *Class) callconv(.c) void {
gobject.ext.ensureType(Command);
gtk.Widget.Class.setTemplateFromResource(
class.as(gtk.Widget.Class),
comptime gresource.blueprint(.{
.major = 1,
.minor = 5,
.name = "command-palette",
}),
);
// Bindings
class.bindTemplateChildPrivate("dialog", .{});
class.bindTemplateChildPrivate("search", .{});
class.bindTemplateChildPrivate("view", .{});
class.bindTemplateChildPrivate("model", .{});
class.bindTemplateChildPrivate("source", .{});
// Template Callbacks
class.bindTemplateCallback("closed", &dialogClosed);
class.bindTemplateCallback("notify_config", &propConfig);
class.bindTemplateCallback("search_stopped", &searchStopped);
class.bindTemplateCallback("search_activated", &searchActivated);
class.bindTemplateCallback("row_activated", &rowActivated);
// Properties
gobject.ext.registerProperties(class, &.{
properties.config.impl,
});
// Signals
signals.trigger.impl.register(.{});
// Virtual methods
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
}
pub const as = C.Class.as;
pub const bindTemplateChildPrivate = C.Class.bindTemplateChildPrivate;
pub const bindTemplateCallback = C.Class.bindTemplateCallback;
};
};
/// Object that wraps around a command.
///
/// As GTK list models only accept objects that are within the GObject hierarchy,
/// we have to construct a wrapper to be easily consumed by the list model.
const Command = extern struct {
pub const Self = @This();
pub const Parent = gobject.Object;
parent: Parent,
pub const getGObjectType = gobject.ext.defineClass(Self, .{
.name = "GhosttyCommand",
.instanceInit = &init,
.classInit = Class.init,
.parent_class = &Class.parent,
.private = .{ .Type = Private, .offset = &Private.offset },
});
const properties = struct {
pub const config = struct {
pub const name = "config";
const impl = gobject.ext.defineProperty(
name,
Self,
?*Config,
.{
.accessor = C.privateObjFieldAccessor("config"),
},
);
};
pub const action_key = struct {
pub const name = "action-key";
const impl = gobject.ext.defineProperty(
name,
Self,
?[:0]const u8,
.{
.default = null,
.accessor = gobject.ext.typedAccessor(
Self,
?[:0]const u8,
.{
.getter = propGetActionKey,
.getter_transfer = .none,
},
),
},
);
};
pub const action = struct {
pub const name = "action";
const impl = gobject.ext.defineProperty(
name,
Self,
?[:0]const u8,
.{
.default = null,
.accessor = gobject.ext.typedAccessor(
Self,
?[:0]const u8,
.{
.getter = propGetAction,
.getter_transfer = .none,
},
),
},
);
};
pub const title = struct {
pub const name = "title";
const impl = gobject.ext.defineProperty(
name,
Self,
?[:0]const u8,
.{
.default = null,
.accessor = gobject.ext.typedAccessor(
Self,
?[:0]const u8,
.{
.getter = propGetTitle,
.getter_transfer = .none,
},
),
},
);
};
pub const description = struct {
pub const name = "description";
const impl = gobject.ext.defineProperty(
name,
Self,
?[:0]const u8,
.{
.default = null,
.accessor = gobject.ext.typedAccessor(
Self,
?[:0]const u8,
.{
.getter = propGetDescription,
.getter_transfer = .none,
},
),
},
);
};
};
pub const Private = struct {
/// The configuration we should use to get keybindings.
config: ?*Config = null,
/// Arena used to manage our allocations.
arena: ArenaAllocator,
/// The command.
command: ?input.Command = null,
/// Cache the formatted action.
action: ?[:0]const u8 = null,
/// Cache the formatted action_key.
action_key: ?[:0]const u8 = null,
pub var offset: c_int = 0;
};
pub fn new(config: *Config, command: input.Command) *Self {
const self = gobject.ext.newInstance(Self, .{
.config = config,
});
const priv = self.private();
priv.command = command.clone(priv.arena.allocator()) catch null;
return self;
}
fn init(self: *Self, _: *Class) callconv(.c) void {
// NOTE: we do not watch for changes to the config here as the command
// palette will destroy and recreate this object if/when the config
// changes.
const priv = self.private();
priv.arena = .init(Application.default().allocator());
}
fn dispose(self: *Self) callconv(.c) void {
const priv = self.private();
if (priv.config) |config| {
config.unref();
priv.config = null;
}
gobject.Object.virtual_methods.dispose.call(
Class.parent,
self.as(Parent),
);
}
fn finalize(self: *Self) callconv(.c) void {
const priv = self.private();
priv.arena.deinit();
gobject.Object.virtual_methods.finalize.call(
Class.parent,
self.as(Parent),
);
}
//---------------------------------------------------------------
fn propGetActionKey(self: *Self) ?[:0]const u8 {
const priv = self.private();
if (priv.action_key) |action_key| return action_key;
const command = priv.command orelse return null;
priv.action_key = std.fmt.allocPrintZ(
priv.arena.allocator(),
"{}",
.{command.action},
) catch null;
return priv.action_key;
}
fn propGetAction(self: *Self) ?[:0]const u8 {
const priv = self.private();
if (priv.action) |action| return action;
const command = priv.command orelse return null;
const cfg = if (priv.config) |config| config.get() else return null;
const keybinds = cfg.keybind.set;
const alloc = priv.arena.allocator();
priv.action = action: {
var buf: [64]u8 = undefined;
const trigger = keybinds.getTrigger(command.action) orelse break :action null;
const accel = (key.accelFromTrigger(&buf, trigger) catch break :action null) orelse break :action null;
break :action alloc.dupeZ(u8, accel) catch return null;
};
return priv.action;
}
fn propGetTitle(self: *Self) ?[:0]const u8 {
const priv = self.private();
const command = priv.command orelse return null;
return command.title;
}
fn propGetDescription(self: *Self) ?[:0]const u8 {
const priv = self.private();
const command = priv.command orelse return null;
return command.description;
}
//---------------------------------------------------------------
/// Return a copy of the action. Callers must ensure that they do not use
/// the action beyond the lifetime of this object because it has internally
/// allocated data that will be freed when this object is.
pub fn getAction(self: *Self) ?input.Binding.Action {
const priv = self.private();
const command = priv.command orelse return null;
return command.action;
}
//---------------------------------------------------------------
const C = Common(Self, Private);
pub const as = C.as;
pub const ref = C.ref;
pub const unref = C.unref;
const private = C.private;
pub const Class = extern struct {
parent_class: Parent.Class,
var parent: *Parent.Class = undefined;
pub const Instance = Self;
fn init(class: *Class) callconv(.c) void {
gobject.ext.registerProperties(class, &.{
properties.config.impl,
properties.action_key.impl,
properties.action.impl,
properties.title.impl,
properties.description.impl,
});
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
gobject.Object.virtual_methods.finalize.implement(class, &finalize);
}
};
};

View File

@@ -39,8 +39,6 @@ pub const Config = extern struct {
Self,
?*gtk.TextBuffer,
.{
.nick = "Diagnostics Buffer",
.blurb = "A TextBuffer that contains the diagnostics.",
.accessor = gobject.ext.typedAccessor(
Self,
?*gtk.TextBuffer,
@@ -52,31 +50,11 @@ pub const Config = extern struct {
},
);
pub const @"gtk-wide-tabs" = gobject.ext.defineProperty(
"gtk-wide-tabs",
Self,
bool,
.{
.nick = "gtk-wide-tabs",
.blurb = null,
.default = false,
.accessor = gobject.ext.typedAccessor(
Self,
bool,
.{
.getter = Self.gtkWideTabs,
},
),
},
);
pub const @"has-diagnostics" = gobject.ext.defineProperty(
"has-diagnostics",
Self,
bool,
.{
.nick = "has-diagnostics",
.blurb = "Whether the configuration has diagnostics.",
.default = false,
.accessor = gobject.ext.typedAccessor(
Self,
@@ -123,12 +101,6 @@ pub const Config = extern struct {
return &self.private().config;
}
/// Returns the current value of gtk-wide-tabs.
pub fn gtkWideTabs(self: *Self) bool {
const config = self.get();
return config.@"gtk-wide-tabs";
}
/// Returns whether this configuration has any diagnostics.
pub fn hasDiagnostics(self: *Self) bool {
const config = self.get();
@@ -163,7 +135,7 @@ pub const Config = extern struct {
return text_buf;
}
fn finalize(self: *Self) callconv(.C) void {
fn finalize(self: *Self) callconv(.c) void {
self.private().config.deinit();
gobject.Object.virtual_methods.finalize.call(
@@ -183,11 +155,10 @@ pub const Config = extern struct {
var parent: *Parent.Class = undefined;
pub const Instance = Self;
fn init(class: *Class) callconv(.C) void {
fn init(class: *Class) callconv(.c) void {
gobject.Object.virtual_methods.finalize.implement(class, &finalize);
gobject.ext.registerProperties(class, &.{
properties.@"diagnostics-buffer",
properties.@"gtk-wide-tabs",
properties.@"has-diagnostics",
});
}

View File

@@ -29,8 +29,6 @@ pub const ConfigErrorsDialog = extern struct {
Self,
?*Config,
.{
.nick = "config",
.blurb = "The configuration that this dialog is showing errors for.",
.accessor = gobject.ext.typedAccessor(
Self,
?*Config,
@@ -67,7 +65,7 @@ pub const ConfigErrorsDialog = extern struct {
});
}
fn init(self: *Self, _: *Class) callconv(.C) void {
fn init(self: *Self, _: *Class) callconv(.c) void {
gtk.Widget.initTemplate(self.as(gtk.Widget));
}
@@ -82,7 +80,7 @@ pub const ConfigErrorsDialog = extern struct {
fn response(
self: *Self,
response_id: [*:0]const u8,
) callconv(.C) void {
) callconv(.c) void {
if (std.mem.orderZ(u8, response_id, "reload") != .eq) return;
signals.@"reload-config".impl.emit(
self,
@@ -92,7 +90,7 @@ pub const ConfigErrorsDialog = extern struct {
);
}
fn dispose(self: *Self) callconv(.C) void {
fn dispose(self: *Self) callconv(.c) void {
const priv = self.private();
if (priv.config) |v| {
v.unref();
@@ -134,7 +132,7 @@ pub const ConfigErrorsDialog = extern struct {
var parent: *Parent.Class = undefined;
pub const Instance = Self;
fn init(class: *Class) callconv(.C) void {
fn init(class: *Class) callconv(.c) void {
gobject.ext.ensureType(Dialog);
gtk.Widget.Class.setTemplateFromResource(
class.as(gtk.Widget.Class),

View File

@@ -0,0 +1,52 @@
const std = @import("std");
const adw = @import("adw");
const gobject = @import("gobject");
const gtk = @import("gtk");
const build_config = @import("../../../build_config.zig");
const adw_version = @import("../adw_version.zig");
const gresource = @import("../build/gresource.zig");
const Common = @import("../class.zig").Common;
/// Debug warning banner. It will be based on adw.Banner if we're using Adwaita
/// 1.3 or newer. Otherwise it will use a gtk.Label.
pub const DebugWarning = extern struct {
const Self = @This();
parent_instance: Parent,
pub const Parent = if (adw_version.supportsBanner()) adw.Bin else gtk.Box;
pub const getGObjectType = gobject.ext.defineClass(Self, .{
.name = "GhosttyDebugWarning",
.instanceInit = &init,
.classInit = &Class.init,
.parent_class = &Class.parent,
});
fn init(self: *Self, _: *Class) callconv(.c) void {
gtk.Widget.initTemplate(self.as(gtk.Widget));
}
const C = Common(Self, null);
pub const as = C.as;
pub const ref = C.ref;
pub const unref = C.unref;
const private = C.private;
pub const Class = extern struct {
parent_class: Parent.Class,
var parent: *Parent.Class = undefined;
pub const Instance = Self;
fn init(class: *Class) callconv(.c) void {
gtk.Widget.Class.setTemplateFromResource(
class.as(gtk.Widget.Class),
comptime gresource.blueprint(.{
.major = 1,
.minor = if (adw_version.supportsBanner()) 3 else 2,
.name = "debug-warning",
}),
);
}
pub const as = C.Class.as;
};
};

View File

@@ -82,7 +82,7 @@ pub const Dialog = extern struct {
var parent: *Parent.Class = undefined;
pub const Instance = Self;
fn init(class: *Class) callconv(.C) void {
fn init(class: *Class) callconv(.c) void {
_ = class;
}

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