Commit Graph

12730 Commits

Author SHA1 Message Date
Mitchell Hashimoto
da165fc3cf input: modify other keys 2 should use all mods, ignore consumed mods (#9289)
Fixes #8900

Our xterm modify other keys state 2 encoding was stripped consumed mods
from the keyboard event. This doesn't match xterm or other popular
terminal emulators (but most importantly: xterm). Use the full set of
mods and add a test to verify this.

Reproduction:

```
printf '\033[>4;2m' 
cat
```

Then press `ctrl+shift+h` and compare across terminals.
2025-10-20 14:41:35 -07:00
Mitchell Hashimoto
0546606e05 build: add -Demit-themes option to emit/omit theme resources (#9288)
We'll backport this to 1.2.x for distros that would prefer this.
2025-10-20 13:14:42 -07:00
Matthew Hrehirchuk
2696d50ca4 feat: added mouse-reporting / toggle-mouse-reporting (#9282)
Closes #8430

A few questions:
* Should I set a default keybind for `toggle-mouse-reporting`? The issue
mentioned one, it's currently unset.
* Am I handling the `toggle-mouse-reporting` action properly in
`performAction` (gtk) / `action` (macos)?

Copilot was used to understand the codebase, but code was authored
manually.
2025-10-19 20:45:37 -07:00
Mitchell Hashimoto
1b86691896 termio: use a union to represent how a process is started (#9278)
This cleans up some of our termio exec code by unifying process launch
state into a single union type. This makes it easier to distinguish
between the current two mutually exclusive modes of launching a process:
fork/exec and flatpak dbus commands.

It also ensures everyplace we touch related to process launching is
forced to address every case (exhaustive switch handling). I did find
one resource cleanup bug based on this cleanup, which is also fixed
here. This just improves memory slightly so it's not a big deal.

If we add future ways to launch processes, we can add a new union case.
For example, I originally had a `posix_spawn` option while I was
experimenting with that before abandoning it (see #9274).
2025-10-19 20:43:28 -07:00
Mitchell Hashimoto
014de2992e macos: goto_split direction is performable (#9284)
Fixes #9283

There was a comment here noting this deficiency. GTK implements this
properly.
2025-10-19 20:29:36 -07:00
Mitchell Hashimoto
c65e837b22 cli: fix +ssh-cache IPv6 address validation (#9281)
The host validation code previously expected IPv6 addresses to be
enclosed in [brackets], but that's not how ssh(1) expects them.

This change removes that requirement and reimplements the host
validation routine to check for valid hostnames and IP addresses (IPv4
and IPv6) using standard routines rather than custom logic.

Fixes #9251
2025-10-19 19:47:41 -07:00
Mitchell Hashimoto
88ec71dd5a build(deps): bump flatpak/flatpak-github-actions from 6.5 to 6.6 (#9279)
Bumps
[flatpak/flatpak-github-actions](https://github.com/flatpak/flatpak-github-actions)
from 6.5 to 6.6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/flatpak/flatpak-github-actions/releases">flatpak/flatpak-github-actions's
releases</a>.</em></p>
<blockquote>
<h2>v6.6</h2>
<ul>
<li>Specify full URL policy when mirroring screenshots</li>
<li>Fix restore cache keys to actually include arch</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="92ae9851ad"><code>92ae985</code></a>
Fix restore cache keys to actually include arch</li>
<li><a
href="b8a638469e"><code>b8a6384</code></a>
Specify full URL policy when mirroring screenshots</li>
<li><a
href="6684584b07"><code>6684584</code></a>
Switch funding to flatpak instead</li>
<li><a
href="e5aa88fb51"><code>e5aa88f</code></a>
readme: Update flathub images list</li>
<li><a
href="b93832bada"><code>b93832b</code></a>
Sync readme from flathub's fork</li>
<li>See full diff in <a
href="10a3c29f01...92ae9851ad">compare
view</a></li>
</ul>
</details>
<br />


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

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

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

---

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

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


</details>
2025-10-19 19:46:46 -07:00
Mitchell Hashimoto
58a1b60a4b build(deps): bump namespacelabs/nscloud-cache-action from 1.2.18 to 1.2.19 (#9280)
Bumps
[namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action)
from 1.2.18 to 1.2.19.
<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.19</h2>
<h2>What's Changed</h2>
<ul>
<li>Add <code>Playwright</code> cache framework by <a
href="https://github.com/rcrowe"><code>@​rcrowe</code></a> in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/40">namespacelabs/nscloud-cache-action#40</a></li>
<li>Add <code>apt</code> cache framework by <a
href="https://github.com/rcrowe"><code>@​rcrowe</code></a> in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/39">namespacelabs/nscloud-cache-action#39</a></li>
<li>Bump GitHub action workflows by <a
href="https://github.com/deining"><code>@​deining</code></a> in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/37">namespacelabs/nscloud-cache-action#37</a></li>
<li>Warn if mounted cache directory already exists by <a
href="https://github.com/rcrowe"><code>@​rcrowe</code></a> in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/38">namespacelabs/nscloud-cache-action#38</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/rcrowe"><code>@​rcrowe</code></a> made
their first contribution in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/40">namespacelabs/nscloud-cache-action#40</a></li>
<li><a href="https://github.com/deining"><code>@​deining</code></a> made
their first contribution in <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/pull/37">namespacelabs/nscloud-cache-action#37</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/namespacelabs/nscloud-cache-action/compare/v1...v1.2.19">https://github.com/namespacelabs/nscloud-cache-action/compare/v1...v1.2.19</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="caff5c9dc5"><code>caff5c9</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/38">#38</a>
from rcrowe/mount-target-exists-error</li>
<li><a
href="4e2102fe86"><code>4e2102f</code></a>
Catch filesystem errors</li>
<li><a
href="e84601ffd1"><code>e84601f</code></a>
Handle case where mount target exists</li>
<li><a
href="4878cb2fed"><code>4878cb2</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/37">#37</a>
from deining/bump-workflows</li>
<li><a
href="818af18748"><code>818af18</code></a>
bump go versions</li>
<li><a
href="bf91808d15"><code>bf91808</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/39">#39</a>
from rcrowe/apt-framework</li>
<li><a
href="7245a34835"><code>7245a34</code></a>
Address feedback with clearer variable names</li>
<li><a
href="bf55a8733d"><code>bf55a87</code></a>
add actions workflow to test</li>
<li><a
href="856ef89a7a"><code>856ef89</code></a>
apt-config is noisy in the logs</li>
<li><a
href="fd911d7189"><code>fd911d7</code></a>
Remove docker-clean script</li>
<li>Additional commits viewable in <a
href="7baedde84b...caff5c9dc5">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.18&new-version=1.2.19)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

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

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

---

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

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


</details>
2025-10-19 19:46:39 -07:00
Jon Parise
e522482710 cli: fix +ssh-cache IPv6 address validation
The host validation code previously expected IPv6 addresses to be
enclosed in [brackets], but that's not how ssh(1) expects them.

This change removes that requirement and reimplements the host
validation routine to check for valid hostnames and IP addresses (IPv4
and IPv6) using standard routines rather than custom logic.
2025-10-19 20:31:32 -04:00
dependabot[bot]
d01697e7d5 build(deps): bump namespacelabs/nscloud-cache-action
Bumps [namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action) from 1.2.18 to 1.2.19.
- [Release notes](https://github.com/namespacelabs/nscloud-cache-action/releases)
- [Commits](7baedde84b...caff5c9dc5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 00:10:08 +00:00
dependabot[bot]
b2559e8d92 build(deps): bump flatpak/flatpak-github-actions from 6.5 to 6.6
Bumps [flatpak/flatpak-github-actions](https://github.com/flatpak/flatpak-github-actions) from 6.5 to 6.6.
- [Release notes](https://github.com/flatpak/flatpak-github-actions/releases)
- [Commits](10a3c29f01...92ae9851ad)

---
updated-dependencies:
- dependency-name: flatpak/flatpak-github-actions
  dependency-version: '6.6'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 00:09:59 +00:00
Mitchell Hashimoto
40e558f953 os: remove unused UrlParsingError (#9275)
This is no longer used as of e5247f6d.
2025-10-19 15:16:45 -07:00
Mitchell Hashimoto
78621622e6 os: add RFC 1123-compliant hostname.isValid (#9276)
std.net.isValidHostname is currently too generous. It considers strings
like ".example.com", "exa..mple.com", and "-example.com" to be valid
hostnames, which is incorrect according to RFC 1123 (the currently
accepted standard).

Until the standard library function is improved, we can use this local
implementation that does follow the RFC 1123 standard.

I asked Claude to perform an audit of the code based on its understand
of the RFC. It suggested some additional test cases and considers the
overall implementation to be robust (its words) and standards compliant.

Ref: https://www.rfc-editor.org/rfc/rfc1123
2025-10-19 15:16:12 -07:00
Jon Parise
010cbce220 os: add RFC 1123-compliant hostname.isValid
std.net.isValidHostname is currently too generous. It considers strings
like ".example.com", "exa..mple.com", and "-example.com" to be valid
hostnames, which is incorrect according to RFC 1123 (the currently
accepted standard).

Until the standard library function is improved, we can use this local
implementation that does follow the RFC 1123 standard.

I asked Claude to perform an audit of the code based on its understand
of the RFC. It suggested some additional test cases and considers the
overall implementation to be robust (its words) and standards compliant.

Ref: https://www.rfc-editor.org/rfc/rfc1123
2025-10-19 14:36:02 -04:00
Jon Parise
73da748390 os: remove unused UrlParsingError
This is no longer used as of e5247f6d.
2025-10-19 13:12:32 -04:00
Mitchell Hashimoto
94c5572029 fix: fish shell integration should not update the universal fish_user_paths variable (#9273)
`fish_add_path` by default updates the `fish_user_paths` universal
variable which makes the modification persist across shell sessions.

The integration also tries to update the `fish_user_paths` when the
desired path already appears in the `PATH` environment variable but not
in `fish_user_paths`. Because `fish_user_paths` will always be inserted
before the inherited `PATH` env. This makes the added path
unintentionally has a higher priority.

This patch fixes the above issues by adding `--global` and `--path`
options to `fish_user_paths` which limits the modification scope and
ensures that the path won't be added if it already exists in `PATH`.

Ref: https://fishshell.com/docs/current/cmds/fish_add_path.html
2025-10-19 08:19:01 -07:00
Sola
c6788dd178 fix: fish shell integration should not modify universal path variable
`fish_add_path` by default updates the `fish_user_paths` universal
variable which makes the modification persist across shell sessions.

The integration also tries to update the `fish_user_paths` when the
desired path already appears in the `PATH` environment variable but
not in `fish_user_paths`. Because `fish_user_paths` will always be
inserted before the inherited `PATH` env. This makes the added path
unintentionally has a higher priority.

This patch makes the above issues by adding `--global` and `--path`
options to `fish_user_paths` which limits the modification scope and
ensures that the path won't be added if it already exists in `PATH`.
2025-10-19 20:46:48 +08:00
Mitchell Hashimoto
f74bfdaa2a Update iTerm2 colorschemes (#9269)
Upstream release:
https://github.com/mbadolato/iTerm2-Color-Schemes/releases/tag/release-20251013-150525-147b9d3
2025-10-18 21:34:50 -07:00
Mitchell Hashimoto
be608ea2d1 renderer: don't allow the scrollbar state to block the renderer (#9270)
This fixes the source of a deadlock that some tip users have hit. If our
surface mailbox is full and there is a dirty scrollbar state, then
drawFrame would block forever trying to queue to the surface mailbox.

We now fail instantly if the queue is full and keep the scrollbar state
dirty. We can try again on the next frame, it's not a critical thing to
get updated.
2025-10-18 21:34:27 -07:00
Mitchell Hashimoto
3a9eedcd15 renderer: don't allow the scrollbar state to block the renderer
This fixes the source of a deadlock that some tip users have hit. If our 
surface mailbox is full and there is a dirty scrollbar state, then
drawFrame would block forever trying to queue to the surface mailbox.

We now fail instantly if the queue is full and keep the scrollbar state
dirty. We can try again on the next frame, it's not a critical thing to
get updated.
2025-10-18 21:30:11 -07:00
mitchellh
92c9ba67d5 deps: Update iTerm2 color schemes 2025-10-19 00:15:26 +00:00
tdslot
be0da4845c 🌐 i18n(locale): add lithuanian language support (#8711)
Co-authored-by: Andrius Budvytis <154380884+abudvytis@users.noreply.github.com>
2025-10-18 19:27:39 +02:00
Mitchell Hashimoto
dffa4f4fc7 macos: use stable display UUID for quick terminal screen tracking (#9256)
NSScreen instances can be garbage collected at any time, even for
screens that remain connected, making NSMapTable with weak keys
unreliable for tracking per-screen state.

This changes the quick terminal to use CGDisplay UUIDs as stable
identifiers, keyed in a strong dictionary. Each entry stores the window
frame along with screen dimensions, scale factor, and last-seen
timestamp.

**This should make quick terminal size restore more stable than 1.2.2.**

Rules for pruning:
- Entries are invalidated when screens shrink or change scale
- Entries persist and update when screens grow (allowing cached state to
work with larger resolutions)
- Stale entries for disconnected screens expire after 14 days.
- Maximum of 10 screen entries to prevent unbounded growth
2025-10-17 21:14:56 -07:00
Mitchell Hashimoto
ea505ec51d macos: use stable display UUID for quick terminal screen tracking
NSScreen instances can be garbage collected at any time, even for
screens that remain connected, making NSMapTable with weak keys
unreliable for tracking per-screen state.

This changes the quick terminal to use CGDisplay UUIDs as stable
identifiers, keyed in a strong dictionary. Each entry stores the
window frame along with screen dimensions, scale factor, and last-seen
timestamp.

Rules for pruning:
- Entries are invalidated when screens shrink or change scale
- Entries persist and update when screens grow (allowing cached state
  to work with larger resolutions)
- Stale entries for disconnected screens expire after 14 days.
- Maximum of 10 screen entries to prevent unbounded growth
2025-10-17 21:04:23 -07:00
Mitchell Hashimoto
3e6bda1fff ci: run release-tip even if prior step failed 2025-10-17 21:03:23 -07:00
Mitchell Hashimoto
5bf05dfe31 macos: make terminal smaller to account for legacy scrollbar (#9255)
https://github.com/ghostty-org/ghostty/discussions/9254

When the preferred scrollbar style is "legacy", the scrollbar takes up
space that offsets the actual terminal. To prevent reflow, we detect
this before the scrollbar becomes visible and shrink our terminal width
to prepare for it.

This doesn't account for the style changing at runtime, yet.

## Demo

Notice even before scrollbars, the `gh` output doesn't wrap.


https://github.com/user-attachments/assets/8716ff4d-0660-48b1-aadb-0d31e0b70fcd
2025-10-17 20:18:10 -07:00
Mitchell Hashimoto
5b7f145640 macos: make terminal smaller to account for legacy scrollbar
When the preferred scrollbar style is "legacy", the scrollbar takes up
space that offsets the actual terminal. To prevent reflow, we detect
this before the scrollbar becomes visible and shrink our terminal width
to prepare for it.

This doesn't account for the style changing at runtime, yet.
2025-10-17 20:08:03 -07:00
Mitchell Hashimoto
e4db7f5487 font: Default to light hinting in FreeType (#9253)
This changes the default FreeType load target to `FT_LOAD_TARGET_LIGHT`,
giving the hinter a lighter touch in line with the default behavior in
most other GTK apps, and adds a load flag such that the old hinting
behavior can be restored via config.

As discussed in
https://github.com/ghostty-org/ghostty/issues/8674#issuecomment-3417082534.
However, this doesn't close that issue, as it still doesn't respect
custom Fontconfig settings. It's just a stopgap solution bringing
Ghostty's defaults more in line with the typical results of not
customizing Fontconfig.
2025-10-17 17:14:57 -07:00
Daniel Wennberg
ad9f9dc11e font: Default to light hinting in FreeType 2025-10-17 15:04:04 -07:00
Mitchell Hashimoto
3b8e683d96 renderer: force a full rebuild on any font grid change (#9252)
Fixes #2731 (again)

This regressed in 1.2 due to the renderer rework missing porting this. I
believe this issue is still valid even with the rework since the font
grid changes the atlas and if there are still cached cells that
reference the old atlas coordinates it will produce garbage.
2025-10-17 14:51:30 -07:00
Mitchell Hashimoto
1cc22f93ca renderer: force a full rebuild on any font grid change
Fixes #2731 (again)

This regressed in 1.2 due to the renderer rework missing porting this. I
believe this issue is still valid even with the rework since the font
grid changes the atlas and if there are still cached cells that
reference the old atlas coordinates it will produce garbage.
2025-10-17 14:46:58 -07:00
Mitchell Hashimoto
063070915f gtk: Scrollbars (#9245)
Fixes #111 

This builds on the prior work and adds scrollbars to the GTK
application. After this PR, both the macOS and GTK applications support
scrollbars and #111 can be closed.

## TODO

- [x] Verify that with text coming out if we manually scroll to the
bottom we bind to the bottom
- [x] Valgrind checks
2025-10-17 09:21:57 -07:00
Mitchell Hashimoto
ed443bc6ed gtk: Scrollbars 2025-10-17 09:19:02 -07:00
Mitchell Hashimoto
a2e95ce7b5 macOS: Remove hidden titlebar safe area and pad document height in SurfaceScrollView (#9241)
Fixes #9233. The issue was that the content view was effectively
truncated by `SurfaceScrollView`s safe area insets covering the titlebar
(I suppose the scroll view doesn't inherit the `ignoresSafeArea`
modifier on `TerminalSplitTreeView` because it's not actually a node in
that tree, it just contains a subview that is). I think it's OK to zero
these insets unconditionally, as I don't think the frame size passed
down from `SurfaceWrapper` will ever overlap with a visible titlebar.

This PR also fixes a somewhat related issue I discovered along the way.
In many cases, the mouse wouldn't work on the first row of text, whether
trying to select text or interact with TUI elements like neovim
bufferlines/tablines. When looking at the inspector while moving the
mouse around, you'd see the mouse position jump discontinuously from a
y-coordinate of 10-20 pixels to -3, i.e., no longer within the surface.

The problem turned out to be that the height of the document view only
included the text lines, not the window padding, while the content view
is sized to the surface including padding. If you imagine the
metaphorical sliding of the viewport up and down the document, and you
require the text to snap to a fixed grid on the viewport, it's clear
that the document must have the same top and bottom padding as the
viewport, otherwise the math breaks at the ends. Sure enough, adding
this padding fixed the problem.

To properly reproduce these issues and see the effect of the fixes, it's
helpful to change the system settings to always show scroll bars
(Appearance -> Show scroll bars -> Always). That's what connecting an
external mouse was all about. You should also remove the debug banner or
use a release build, otherwise the banner takes the place of the hidden
titlebar and conceals the issue.
2025-10-17 06:34:25 -07:00
Daniel Wennberg
51b2374616 Add window padding to scrollView document height 2025-10-17 00:14:21 -07:00
Daniel Wennberg
ffead466c7 Remove hidden titlebar safe area for SurfaceScrollView 2025-10-17 00:06:00 -07:00
Mitchell Hashimoto
58699c7992 macOS: remove background from SurfaceScrollView (#9234)
<img width="1157" height="126" alt="image"
src="https://github.com/user-attachments/assets/07f67e6c-76b3-4d7d-ba44-37e85b8660cc"
/>
2025-10-16 14:56:47 -07:00
Lars
cc91e2ad16 macOS: remove background from SurfaceScrollView 2025-10-16 23:52:07 +02:00
Mitchell Hashimoto
0e0bbfaa61 macOS: Scrollbars (#9232)
Completes #111 for macOS

This builds on #9225 and adds the native, macOS GUI scrollbars for
terminals.

This doesn't do GTK, but all the groundwork is there to make this easy
on GTK, depending on how scrollviews work there. I have to look into
that still. But in theory all the information and controls we provide
out of core are generic to _any_ scrollbar drawing.

## Demo


https://github.com/user-attachments/assets/85683bf9-1117-4f32-aaec-d926edd68c39

## Details

- The scrollbars respect your macOS system settings on style, color,
visibility.
- A new configuration `scrollbar` controls whether scrollbars are
visible (defaults to `system` allowing the system to choose).
- There is a new keybind action `scroll_to_row:N` that lets you jump to
an absolute row number N. This is implemented efficiently. This is how
grabbing the knob and scrolling works.
2025-10-16 14:09:33 -07:00
Mitchell Hashimoto
4b34b2389a config: add scrollbar config to control when scrollbars appear 2025-10-16 14:06:48 -07:00
Mitchell Hashimoto
7207ff08d5 macos: SurfaceScrollView 2025-10-16 14:06:46 -07:00
Mitchell Hashimoto
2937aff513 gtk: mark scrollbar as unimplemented 2025-10-16 09:36:47 -07:00
Mitchell Hashimoto
c86266cd90 input: scroll_to_row action 2025-10-16 09:11:03 -07:00
Mitchell Hashimoto
135136f733 terminal: PageList scroll to absolute row function 2025-10-16 09:11:03 -07:00
Mitchell Hashimoto
da7736cd44 renderer: emit scrollbar apprt event when scrollbar changes 2025-10-15 21:45:01 -07:00
Mitchell Hashimoto
5a9bd0e49e snap: update to Zig 0.15.2 2025-10-15 20:04:37 -07:00
dependabot[bot]
3ffbd87a0f build(deps): bump cachix/install-nix-action from 31.8.0 to 31.8.1 (#9226)
Bumps
[cachix/install-nix-action](https://github.com/cachix/install-nix-action)
from 31.8.0 to 31.8.1.
<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.8.1</h2>
<h2>What's Changed</h2>
<ul>
<li>nix: 2.32.0 -&gt; 2.32.1 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/258">cachix/install-nix-action#258</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/cachix/install-nix-action/compare/v31...v31.8.1">https://github.com/cachix/install-nix-action/compare/v31...v31.8.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="fd24c48048"><code>fd24c48</code></a>
Merge pull request <a
href="https://redirect.github.com/cachix/install-nix-action/issues/258">#258</a>
from cachix/create-pull-request/patch</li>
<li><a
href="a55fd2d847"><code>a55fd2d</code></a>
nix: 2.32.0 -&gt; 2.32.1</li>
<li>See full diff in <a
href="7ab6e7fd29...fd24c48048">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.8.0&new-version=31.8.1)](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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-15 19:43:35 -07:00
dependabot[bot]
123d23682a build(deps): bump namespacelabs/nscloud-setup-buildx-action from 0.0.19 to 0.0.20 (#9227)
Bumps
[namespacelabs/nscloud-setup-buildx-action](https://github.com/namespacelabs/nscloud-setup-buildx-action)
from 0.0.19 to 0.0.20.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/namespacelabs/nscloud-setup-buildx-action/releases">namespacelabs/nscloud-setup-buildx-action's
releases</a>.</em></p>
<blockquote>
<h2>v0.0.20</h2>
<h2>What's Changed</h2>
<ul>
<li>Add wait-for-builder input to eagerly start build clusters and wait
for them by <a
href="https://github.com/annervisser"><code>@​annervisser</code></a> in
<a
href="https://redirect.github.com/namespacelabs/nscloud-setup-buildx-action/pull/11">namespacelabs/nscloud-setup-buildx-action#11</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/annervisser"><code>@​annervisser</code></a>
made their first contribution in <a
href="https://redirect.github.com/namespacelabs/nscloud-setup-buildx-action/pull/11">namespacelabs/nscloud-setup-buildx-action#11</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/namespacelabs/nscloud-setup-buildx-action/compare/v0...v0.0.20">https://github.com/namespacelabs/nscloud-setup-buildx-action/compare/v0...v0.0.20</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="91c2e65377"><code>91c2e65</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-setup-buildx-action/issues/11">#11</a>
from namespacelabs/add-wait-for-builder-input-to-eager...</li>
<li><a
href="459dd43ae1"><code>459dd43</code></a>
Add wait-for-builder input to eagerly start build clusters and wait for
them</li>
<li>See full diff in <a
href="7020d7d8e6...91c2e65377">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=namespacelabs/nscloud-setup-buildx-action&package-manager=github_actions&previous-version=0.0.19&new-version=0.0.20)](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>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-15 19:43:22 -07:00
Mitchell Hashimoto
e1b527fb9a core: PageList tracks minimum metadata for rendering a scrollbar (#9225)
Related to #111

This adds the necessary logic and data for the `PageList` data structure
to keep track of **total length** of the screen, **offset** into the
viewport, and **length** of the viewport. These three values are
necessary to _render_ a scrollbar. This PR updates the renderer to grab
this information but stops short of actually drawing a scrollbar (which
we'll do with native UI), in the interest of having a PR that doesn't
contain too many changes.

**This doesn't yet draw a scrollbar, these are just the internal changes
necessary to support it.**

## Background

The `PageList` structure is very core to how we represent terminal
state. It maintains a doubly linked list of "pages" (not literally
virtual memory pages, but close). Each page stores cell information,
styles, hyperlinks, etc fully self-contained in a contiguous sets of VM
pages using offset addresses rather than full pointers. **Pages are not
guaranteed to be equal sizes.** (This is where scrollbars get difficult)

Because it is a linked list structure of non-equal sized nodes, it isn't
amenable to typical scrollbar behavior. A scrollbar needs to know: full
size, offset, and length in order to draw the scrollbar properly.
Getting these values naively is `O(N)` within the data structure that is
on the hottest IO performance path in all of Ghostty.

## Implementation

### PageList

We now maintain two cached values for **total length** and **viewport
offset**.

The total length is relatively straightforward, we just have to be
careful to update it in every operation that could add or remove rows.
I've done this and ensured that every place we update it is covered with
unit test coverage.

The viewport offset is nasty, but I came up with what I believe is a
good solution. The viewport when arbitrarily scrolled is defined as a
direct pointer to the linked list node plus a row offset into that node.
The only way to calculate offset from the top is `O(N)`.

But we have a couple shortcuts:

1. If the viewport is at the bottom (most common) or top, calculating
the offset is `O(1)`: bottom is `total_rows - active_rows`, both readily
available. And top is `0` by definition.

2. Operations on the PageList typically add or remove rows. We don't do
arbitrary linked list surgery. If we instrument those areas with delta
updates to our cache, we can avoid the `O(N)` cost for most operations,
including scrolling a scrollbar. The only expensive operation is a full,
arbitrary jump (new node pointer).

Point 1 was quick to implement, so I focused all the complexity on point
2. Whenever we have an operation that adds or removes rows (for example
pruning the scroll back, adding more, erase rows within the active area,
etc.) then I do the math to calculate the delta change required for the
offset if we've already calculated it, and apply that directly.

### Renderer

The other issue was how to notify the apprts of scrollbar state. Sending
messages on any terminal change within the IO thread is a non-option
because (1) sending messages is slow (2) the terminal changes a lot and
(3) any slowness in the IO thread slows down overall terminal
throughput.

The solution was to **trigger scrollbar notifications with the renderer
vsync**. We read the scrollbar information when we render a frame,
compare it to renderer previous state, and if the scrollbar changed,
send a message to the apprt _after the frame is GPU-renderer_.

The renderer spends _most_ of its time sleeping compared to the IO
thread, and has more opportunities for optimizing its awake time.
Additionally, there's no reason to update the scrollbar information if
the renderer hasn't rendered the new frames because the user can't even
see the stuff the scrollbar wants to scroll to. We're talking about
millisecond scale stuff here at worst but it adds up.

## Performance

No noticeable performance impact for the additional metrics:

<img width="1012" height="738" alt="image"
src="https://github.com/user-attachments/assets/4ed0a3e8-6d76-40c1-b249-e34041c2f6fd"
/>

## AI Usage

I used Amp to help audit the codebase and write tests. I wrote all the
main implementation code manually. I came up with the main design
myself. Relevant threads:

-
https://ampcode.com/threads/T-95fff686-75bb-4553-a2fb-e41fe4cd4b77#message-0-block-0
-
https://ampcode.com/threads/T-48e9a288-b280-4eec-83b7-ca73d029b4ef#message-91-block-0

## Future

This is just the internal changes necessary to _draw_ a scrollbar. There
will be other changes we'll need to add to handle grabbing and actually
jumping the scrollbar. I have a good idea of how to implement those
performantly as well.
2025-10-15 19:42:49 -07:00
Mitchell Hashimoto
014a2e0042 termio: color change operations must gracefully handle renderer mailbox full (#9224)
Fixes #9191

This changes our color change operations from writing to the renderer
mailbox directly to using our `rendererMailboxWriter` function which
handles the scenario where the mailbox is full by yielding the lock,
waking up the renderer, and retrying later.

This is a known deadlock scenario we've worked around since the private
beta days, but unfortunately this slipped through and I didn't catch it
in review.

What happens here is it's possible with certain escape sequences for the
IO thread to saturate other mailboxes with messages while holding the
terminal state lock. This can happen to any thread. This ultimately
leads to starvation and all threads deadlock.

Our IO thread is the only thread that produces this kind of massive
stream of events while holding the lock, so we have helpers in it to
attempt to queue (cheap, fast) and if that fails then to yield the lock,
wakeup the target thread, requeue, and grab the lock again (expensive,
slow).
2025-10-15 16:01:26 -07:00