Fixes https://github.com/ghostty-org/ghostty/discussions/8697 by making
`OK` the suggested default and activating it by default.
Previously `OK` was `destructive` which imo is not a good approach for
just setting a terminal title.
Follow-up to #8720 adding
* Two improvements to FreeType glyph measurements:
- Ensuring that glyphs are measured with the same hinting as they are
rendered, ref
[#8720#issuecomment-3305408157](https://github.com/ghostty-org/ghostty/pull/8720#issuecomment-3305408157);
- For outline glyphs, using the outline bbox instead of the built-in
metrics, like `renderGlyph()`.
* Basic unit tests for face metrics and their estimators, using the
narrowest and widest fonts from the resource directory, Cozette Vector
and Geist Mono.
---
I also made one unrelated change to `freetype.zig`, replacing
`@alignCast(@ptrCast(...))` with `@ptrCast(@alignCast(...))` on line
173. Autoformatting has been making this change on every save for weeks,
and reverting the hunk before each commit is getting old, so I hope it's
OK that I use this PR to upstream this decree from the formatter.
Powerline glyphs were treated as whitespace, giving the preceding cell a
constraint width of 2 and cutting off icons in people's prompts and
statuslines. It is however correct to not treat Powerline glyphs like
other Nerd Font symbols; they should simply be treated as normal
characters, just like their relatives in the block elements unicode
block.
This resolves
https://discord.com/channels/1005603569187160125/1417236683266592798
(never promoted to an issue, but real and easy to reproduce).
**Tip**
<img width="215" height="63" alt="Screenshot 2025-09-21 at 16 57 58"
src="https://github.com/user-attachments/assets/81e770c5-d688-4d8e-839c-1f4288703c06"
/>
**This PR**
<img width="215" height="63" alt="Screenshot 2025-09-21 at 16 58 42"
src="https://github.com/user-attachments/assets/5d2dd770-0314-46f6-99b5-237a0933998e"
/>
The constraint width logic was untested but contains some quite subtle
interactions, so I wrote a suite of tests covering the cases I'm aware
of.
While working on this code I also resolved a TODO comment to add all the
box drawing/block element type characters to the set of codepoints
excluded from the minimum contrast settings.
> This PR will probably need a rebase on the final outcome of #8550 and
~#8552~ #8580, but I'm putting it out here so folks can begin taking a
look if they want.
This is a rewrite of the code that applies scaling and alignment
constraints. The main intention is to further improve how Nerd Font
icons are matched to the primary font. This PR aligns the calculations
more closely with how the Nerd Font `font-patcher` script works, except
in two cases where we can easily do something unambiguously better (one
because of what's arguably a bug in the script, and one because we do
multi-cell alignment with knowledge of the pixel-rounded cell grid).
A goal of the rewrite is to make the scaling and alignment calculations
as clear and easy to follow as possible.
I'll lead with some screenshots. First the status quo, then this PR.
<img width="505" height="357" alt="Screenshot 2025-09-07 at 17 23 51"
src="https://github.com/user-attachments/assets/8e3ff9fd-3b66-4d54-be38-d54cf3b6cc5b"
/><img width="505" height="357" alt="Screenshot 2025-09-07 at 17 20 39"
src="https://github.com/user-attachments/assets/84fbe076-2e3f-4879-b9b2-91ce86b9ef5f"
/>
Relevant specs: macOS; 1920x1080; Ghostty config:
```ini
font-family = "CommitMono"
font-size = "15"
adjust-cell-height = "+20%"
```
**Points to note**
* Icons are generally larger, making better use of the available space.
* Icons are aligned nearly a pixel lower, better matching the text. This
is because alignment is now calculated from face metrics/bearings, not
the pixel-rounded cell. (See more below.)
* Relative sizes are better matched. Note especially that tall and
narrow icons, like the git branch symbol and icons depicting sheets of
paper, look conspicuously small in the status quo. With this PR, they're
better matched to other icons.
* Look at the letter Z icon I use as prompt character for zsh. It's
_tiny_ in the status quo, but properly sized with this PR. This
demonstrates the most important and clear-cut improvement we make over
`font-patcher`. (See more below.)
* Icons wider than a single cell are now left-aligned rather than
centered across two cells. I think this is preferable and makes better
use of space in most relevant contexts.
- Consider a Neovim bufferline showing the buffer title as a filetype
icon followed by the file name. Padding on the left would be a waste of
space, but having that extra space on the right can improve legibility.
- In listings, such as in the screenshots, columns look tidier when
their left edges are straight rather than ragged.
- This is how `font-patcher` does alignment, and thus what Nerd Font
users and UI designers expect.
**Implementation details**
I won't get too deep in the weeds here; see the code and comments. In
brief:
* `size_horizontal` and `size_vertical` are combined to a single `size`,
which can be `.none, .stretch, .fit, .cover` or `.fit_cover1`. The
latter implements the `pa` rule from `font-patcher`, except it works
better for icons that are small before scaling, like the letter Z prompt
in the screenshots. In short, it preserves aspect ratio while clamping
the size such that the icon `.cover`s at least one cell and `.fit`s
within the available space. See code comments and
ryanoasis/nerd-fonts/pull/1926 for details.
* An alignment mode `.center1` is added, implementing the centering rule
from `font-patcher` that I explained/defended above. In short, we center
the icon _in the first cell_, even it's allowed to span multiple cells.
For icons wider than a single cell, the lower bound that prevents them
from protruding to the left kicks in and turns this into left-alignment.
We keep the regular `.center` rule around for use with emojis, et
cetera.
* Scaling and alignment calculations only use the unrounded face metrics
and bearings. This ensures that pixel rounding of the cell and baseline,
and `adjust-cell-{width,height}`, don't affect scaling or relative
alignment; the icons are always scaled and aligned to the _face_. (The
one place we need to use cell metrics in the calculations is when we use
`cell_width` to obtain the inter-cell padding needed to correctly center
or right-align a glyph across two cells.)
- We can do this with impunity because we're blessed with sprite glyphs
in place of the "icons" that are actually box drawing and block graphics
characters 🙌
**Guide**
The meat of the changes is 100 % in `src/font/face.zig` and
`src/font/nerd_font_codegen.py`. Changes to other files only amount to
a) adding/changing some struct fields to get numbers to where they need
to be (see `src/font/Metrics.zig`), and b) collateral updates to make
otherwise unchanged code and tests work with/take advantage of the
modified structs.
Most files should have a clear and friendly diff. The exception is the
bottom half of `src/font/face.zig`, where the diff is meaningless and
the new code should just be reviewed on its own merits. This is the part
where the `constrain` function is rewritten and refactored. Scarred by
countless hours perusing `font-patcher`, I tried hard to make the math
and logic easy to follow here. I hope I have succeeded 🤞
Fixes#8944
When we drag the only tab out of the tab overview, this triggers an
`n-pages` signal with 0 pages. If we close the window in this state, it
causes both Ghostty to exit AND the drag/drop to fail. Even if we
pre-empt Ghostty exiting by modifying the application class, the
drag/drop still fails and the application leaks memory and enters a bad
state.
The solution is to keep the window open if we go to `n-pages == 0` and
we have the tab overview open.
Interestingly, if you click to close the final tab from the tab
overview, Adwaita closes the tab overview so it still triggers the
window closing behavior (this is good, this is desired).
Fixes#8944
When we drag the only tab out of the tab overview, this triggers
an `n-pages` signal with 0 pages. If we close the window in this state,
it causes both Ghostty to exit AND the drag/drop to fail. Even if we
pre-empt Ghostty exiting by modifying the application class, the
drag/drop still fails and the application leaks memory and enters a bad
state.
The solution is to keep the window open if we go to `n-pages == 0` and
we have the tab overview open.
Interestingly, if you click to close the final tab from the tab
overview, Adwaita closes the tab overview so it still triggers the
window closing behavior (this is good).
Resolves Issue: #8670
Now precision and discrete scrolling can be scaled independently.
Supports following configuration,
```code
# Apply everywhere
mouse-scroll-multiplier = 3
# Apply separately
mouse-scroll-multiplier = precision:0.1,discrete:3 (default)
# Also it's order agnostic
mouse-scroll-multiplier = discrete:3,precision:2
# Apply one, default other
mouse-scroll-multiplier = precision:2
```
The default precision value is set 0.1, as it felt natural to me at
least on my track-pad. I've also set the min clamp value precision to
0.1 as 0.01 felt kind of useless to me but I'm unsure.
This adds functions to extra data out of OSC commands, but it is mostly
boilerplate since I only added one valid data extraction. 😄 The example
was updated to show this.
This also changes OSC strings to be null-terminated to ease lib-vt
integration. This shouldn't have any practical effect on terminal
performance, but it does lower the maximum length of OSC strings by 1
since we always reserve space for the null terminator.
This also changes OSC strings to be null-terminated to ease lib-vt
integration. This shouldn't have any practical effect on terminal
performance, but it does lower the maximum length of OSC strings by 1
since we always reserve space for the null terminator.
Fixes various issues:
- C ABI detection was faulty, which caused some Zig programs to use the
C ABI mode and some C programs not to. Let's be explicit.
- Unit tests now tests C ABI mode.
- Build binary no longer rebuilds on any terminal change (a regression).
- Zig programs can choose to depend on the C ABI version of the terminal
lib by using the `ghostty-vt-c` module.
Fixes various issues:
- C ABI detection was faulty, which caused some Zig programs to use
the C ABI mode and some C programs not to. Let's be explicit.
- Unit tests now tests C ABI mode.
- Build binary no longer rebuilds on any terminal change (a regression).
- Zig programs can choose to depend on the C ABI version of the terminal
lib by using the `ghostty-vt-c` module.
This adds more of the OSC parsing API to the C library of
`libghostty-vt`. This adds the following:
* `ghostty_osc_next` - Push a single character into the OSC parser
* `ghostty_osc_reset` - Reset the parser state and free any temporary
memory
* `ghostty_osc_end` - End a parsing sequence and return the parsed
command
* `ghostty_osc_command_type` - Return the type of command parsed
* `examples/c-vt` is updated to use these new APIs
* Our Zig `osc.Command` tagged union is updated to use a new comptime
func to generate an ABI compatible tag for the C lib.
* **Important change:** Our Zig `osc.Parser.end` function was modified
to return a _pointer_ to the command within its own structure memory
rather than a copy. This eases the C API. This impacts the Zig side but
we ultimately copy it again [for now] in the main `terminal.Parser` so
end result is the same.
* Unit tests cover even the C lib
* Shuffled some code for maintainability
The plan is to use this opaque type with getters to ease ABI
compatibility going forward.
Related to #8924
Zig currenly has a bug where it crashes when compiling Ghostty on
systems with more than 32 cpus (See the linked issue for the gory
details). As a temporary hack, use `sched_setaffinity` on Linux systems
to limit the compile to the first 32 cores. Note that this affects the
build only. The resulting Ghostty executable is not limited in any way.
This is a more general fix than wrapping the Zig compiler with
`taskset`. First of all, it requires no action from the user or
packagers. Second, it will be easier for us to remove once the upstream
Zig bug is fixed.
Related to #8924
Zig currenly has a bug where it crashes when compiling Ghostty on
systems with more than 32 cpus (See the linked issue for the gory
details). As a temporary hack, use `sched_setaffinity` on Linux systems
to limit the compile to the first 32 cores. Note that this affects the
build only. The resulting Ghostty executable is not limited in any way.
This is a more general fix than wrapping the Zig compiler with
`taskset`. First of all, it requires no action from the user or
packagers. Second, it will be easier for us to remove once the upstream
Zig bug is fixed.
Hi!
I'm a full Zig noob but [Mitchell's recent
post](https://mitchellh.com/writing/libghostty-is-coming) made me want
to clone the repo and take a look at the tooling.
My first attempt at running examples though VSCode failed because the
latest version of Zig is 0.15.1, but Ghostty requires Zig 0.14*. When
configuring the extension to use a compatible version if Zig, it
suggested pinning the version in a .zigversion file. I'm not familiar
with the pattern, but if it can help someone else's onboarding, I
figured I'd open a PR to suggest the change.
Cheers
*edit: I had a hard time figuring that out
Fix provided by @jcollie
The swift `open_config` action was triggering an allocation error
`error(gpa): Allocation size 41 bytes does not match free size 40.`.
> A string that was created as a `[:0]const u8` was cast to `[]const u8`
and then freed. The sentinel is the off-by-one.
@jcollie
For full context, see
https://discord.com/channels/1005603569187160125/1420367156071239820
Co-authored-by: Jeffrey C. Ollie <jcollie@dmacc.edu>
This is nicer because it only sets the filetype if it hasn't already
been set. :setf[iletype] has been available since vim version 6.
See: https://vimhelp.org/options.txt.html#%3Asetf
Bumps
[namespacelabs/nscloud-cache-action](https://github.com/namespacelabs/nscloud-cache-action)
from 1.2.17 to 1.2.18.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="7baedde84b"><code>7baedde</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/36">#36</a>
from namespacelabs/niklas-docs</li>
<li><a
href="72a48b9085"><code>72a48b9</code></a>
fix docs links</li>
<li><a
href="f5a0d9e059"><code>f5a0d9e</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/35">#35</a>
from namespacelabs/niklas-workflow</li>
<li><a
href="7bb48a0f26"><code>7bb48a0</code></a>
skip bundle exec</li>
<li><a
href="32d69b87dc"><code>32d69b8</code></a>
Merge pull request <a
href="https://redirect.github.com/namespacelabs/nscloud-cache-action/issues/34">#34</a>
from namespacelabs/niklas-apple-caches</li>
<li><a
href="a49d9d84e9"><code>a49d9d8</code></a>
Add experimental cache modes for Xcode, Swift, Ruby and CocoaPods</li>
<li>See full diff in <a
href="a289cf5d2f...7baedde84b">compare
view</a></li>
</ul>
</details>
<br />
[](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>
This is nicer because it only sets the filetype if it hasn't already
been set. :setf[iletype] has been available since vim version 6.
See: https://vimhelp.org/options.txt.html#%3Asetf