Fixes#5552
This makes the mentioned actions performable. This isn't perfect, but it
does so in a way that resolves the user issue in #5552. This commit
returns an action is NOT performed if it doesn't have splits or tabs
(respectiely for the actions), but also reports its ALWAYS performed if
it does.
This latter logic isn't accurate: we should only return performable if
it was actually done. So for example, goto_split:top should do nothing
if we're already at the top. But, we report it as performed today.
This is good enough to resolve the issue and fix the core problem faced
for 1.1.0.
Fixes#5552
This makes the mentioned actions performable. This isn't perfect, but it
does so in a way that resolves the user issue in #5552. This commit
returns an action is NOT performed if it doesn't have splits or tabs
(respectiely for the actions), but also reports its ALWAYS performed if
it does.
This latter logic isn't accurate: we should only return performable if
it was actually done. So for example, goto_split:top should do nothing
if we're already at the top. But, we report it as performed today.
This is good enough to resolve the issue and fix the core problem faced
for 1.1.0.
Fixes#5448
We previously removed the ctrl modifier for text commit (IME-style) to
workaround a libghostty quirk (as noted in the comment in the diff). But
this broke other keyboard layouts.
This commit attempts to clean this up slightly -- but not completely --
by removing that hack, and only modifying the ctrl behavior for the
UCKeyTranslate call.
Long term, I plan to remove UCKeyTranslate completely, as noted in the
todo comment already written just below this diff.
This fixes the aforementioned issue and hopefully doesn't regress any
other behavior. I tested the following:
1. Dvorak Ctrl characters
2. Ergo-L Ctrl characters
3. US standard Ctrl characters
4. Japanese IME input Ctrl input to modify IME state
Fixes#5448
We previously removed the ctrl modifier for text commit (IME-style)
to workaround a libghostty quirk (as noted in the comment in the diff).
But this broke other keyboard layouts.
This commit attempts to clean this up slightly -- but not completely --
by removing that hack, and only modifying the ctrl behavior for the
UCKeyTranslate call.
Long term, I plan to remove UCKeyTranslate completely, as noted in the
todo comment already written just below this diff.
This fixes the aforementioned issue and hopefully doesn't regress any
other behavior. I tested the following:
1. Dvorak Ctrl characters
2. Ergo-L Ctrl characters
3. US standard Ctrl characters
4. Japanese IME input Ctrl input to modify IME state
* implement `yQuads()` and `draw_octant()`, pretty obvious extensions of
existing code. to allocate up to 3 potential remainder lines, consider
that octants will often appear in a rectangular subset of the terminal.
we want the distributed excess uniformly distributed across such a
region. so:
* one excess row: break symmetry in any direction (pick an arbitrary
tetrad and use it everywhere)
* two excess rows: go to alternating tetrads
* three excess rows: break symmetry, do not use three contiguous tetrads
* our `Octant`s are octary arrays of `bool`, provided as a somewhat
opaque constant table
* the 8-line copy-and-paste draw based on the `Octant` is not the
prettiest thing in the known universe
* we could generalize `draw_sextant()` and `draw_octant()` like
notcurses did, almost certainly
* oh bird thou never wert
with that said, i don't think `draw_octant()` is actually being called
lol, so let's not merge this yet. happy to hear early feedback, though.
Adds buildtime and comptime checks to make sure that Blueprints/UI files
are availble and correctly formed. Will also compile Blueprints to UI
files so that they are available to GTK code.
Fixes#5718
When a terminal is resized with text reflow (i.e. soft-wrapped text),
the cursor is generally reflowed with it.
For example, imagine a terminal window 5-columns wide and you type the
following without pressing enter. The cursor is on the X.
```
OOOOO
OOX
```
If you resize the window now to 8 or more columns, this happens, as
expected:
```
OOOOOOOX
```
As expected, the cursor remains on the "X". This behaves like any other
text input...
Terminals also provide an escape sequence to
[save the cursor (ESC 7 aka
DECSC)](https://ghostty.org/docs/vt/esc/decsc). This includes, amongst
other things, the cursor position. The cursor can be restored with
[DECRC](https://ghostty.org/docs/vt/esc/decrc).
The behavior of the position of the _saved cursor_ in the context of
text reflow is unspecified and varies wildly between terminals Ghostty
does this right now (as do many other terminals):
```
OOOOOOOO
X
```
This commit changes the behavior so that we reflow the saved cursor.
Adds buildtime and comptime checks to make sure that Blueprints/UI files
are availble and correctly formed. Will also compile Blueprints to UI
files so that they are available to GTK code.
Fixes#5718
When a terminal is resized with text reflow (i.e. soft-wrapped text), the cursor
is generally reflowed with it.
For example, imagine a terminal window 5-columns wide and you type the
following without pressing enter. The cursor is on the X.
```
OOOOO
OOX
```
If you resize the window now to 8 or more columns, this happens, as expected:
```
OOOOOOOX
```
As expected, the cursor remains on the "X". This behaves like any other text
input...
Terminals also provide an escape sequence to
[save the cursor (ESC 7 aka DECSC)](https://ghostty.org/docs/vt/esc/decsc).
This includes, amongst other things, the cursor position. The cursor can be
restored with [DECRC](https://ghostty.org/docs/vt/esc/decrc).
The behavior of the position of the _saved cursor_ in the context of text
reflow is unspecified and varies wildly between terminals Ghostty does this
right now (as do many other terminals):
```
OOOOOOOO
X
```
This commit changes the behavior so that we reflow the saved cursor.
As pointed out by @tristan957 the standard path for including the
Adwaita header file is simply "adwaita.h". While it may have been
necessary in the past to use a non-standard include path, that no longer
appears to be the case.
As pointed out by @tristan957 the standard path for including the
Adwaita header file is simply "adwaita.h". While it may have been
necessary in the past to use a non-standard include path, that no longer
appears to be the case.
Caused by #5650
I actually don't understand how this didn't happen before or why we
didn't notice it but it seems like the envmap was never freed. In the
latest debug builds prior to this build GPA reports the leak.
We should free the envmap when the subprocess is deinitialized. But also
we can free the env map as soon as we start the subprocess which saves
some small amount of memory at runtime.
Additionally, we should only be freeing the envmap on error if we
created it.
Caused by #5650
I actually don't understand how this didn't happen before or why we
didn't notice it but it seems like the envmap was never freed. In the
latest debug builds prior to this build GPA reports the leak.
We should free the envmap when the subprocess is deinitialized. But also
we can free the env map as soon as we start the subprocess which saves
some small amount of memory at runtime.
Additionally, we should only be freeing the envmap on error if we
created it.
This should help with API rate limits being hit by macOS builders since
they can't use the Namespace cache that Linux builders can use to cache
Zig dependencies. It will need to be run by Mitchell once so that the
Cachix action can push everything up to the cache and then the full
benefits should be seen. Not sure how using `--system` on all the macOS
builds will affect things overall but it doesn't seem to have affected
the CI.
Partial fixes#5552 (for GTK).
This PR adds the core infrastructure for keybind actions that are
implemented as runtime app actions to be performable. This is done by
having `rt_app.performAction` return a boolean. By default all runtime
app actions return `true` (the action was performed) unless they are
modified to return `true`/`false` as appropriate.
The GTK apprt is modified so that `goto_split`, `previous_tab`,
`next_tab`, `last_tab`, and `goto_tab` are performable. macOS support
will need to be added in a subsequent commit.
This doesn't completely solve the issue for the OP because if the
`goto_split` isn't performable there is no fallback to`previous_tab` or
`next_tab`.
I don't think that the approach taken in #5579 is the right one as it
conflates split and tab navigation unconditionally which I don't think
is what everyone would want. Either a separate action that explicitly
combines the actions or a solution to #3175 will be the ultimate
solution I believe.
This is just a fun change to add a bunch of alternate icons. We don't
want to add too many since this increases the final bundle size but we
also want to have some fun. :)
`WINDOWID` is the conventional environment variable for scripts that
want to know the X11 window ID of the terminal, so that it may call
tools like `xprop` or `xdotool`. We already know the window ID for
window protocol handling, so we might as well throw this in for
convenience.
Originally suggested by #4299
`WINDOWID` is the conventional environment variable for scripts that
want to know the X11 window ID of the terminal, so that it may call
tools like `xprop` or `xdotool`. We already know the window ID for
window protocol handling, so we might as well throw this in for
convenience.
Fixes https://github.com/ghostty-org/ghostty/issues/4958
## Changes
1. Fixed documentation generation in `actions.mdx`:
- Fixed an issue where the last action's documentation was [not properly
generated](fe6c69263c/docs/config/keybind/reference.mdx (crash))
- Ensured all actions' documentation is correctly included in the output
2. Improved `ghostty +list-actions --docs` command output formatting:
- Grouped related actions together with shared documentation
- Added proper spacing between action groups
<details>
<summary>ghostty-dev +list-actions --docs</summary>
```
ignore:
Ignore this key combination, don't send it to the child process, just
black hole it.
unbind:
This action is used to flag that the binding should be removed from
the set. This should never exist in an active set and `set.put` has an
assertion to verify this.
csi:
Send a CSI sequence. The value should be the CSI sequence without the
CSI header (`ESC [` or `\x1b[`).
esc:
Send an `ESC` sequence.
text:
Send the given text. Uses Zig string literal syntax. This is currently
not validated. If the text is invalid (i.e. contains an invalid escape
sequence), the error will currently only show up in logs.
cursor_key:
Send data to the pty depending on whether cursor key mode is enabled
(`application`) or disabled (`normal`).
reset:
Reset the terminal. This can fix a lot of issues when a running
program puts the terminal into a broken state. This is equivalent to
when you type "reset" and press enter.
If you do this while in a TUI program such as vim, this may break
the program. If you do this while in a shell, you may have to press
enter after to get a new prompt.
copy_to_clipboard:
paste_from_clipboard:
paste_from_selection:
Copy and paste.
copy_url_to_clipboard:
Copy the URL under the cursor to the clipboard. If there is no
URL under the cursor, this does nothing.
increase_font_size:
decrease_font_size:
Increase/decrease the font size by a certain amount.
reset_font_size:
Reset the font size to the original configured size.
clear_screen:
Clear the screen. This also clears all scrollback.
select_all:
Select all text on the screen.
scroll_to_top:
scroll_to_bottom:
scroll_page_up:
scroll_page_down:
scroll_page_fractional:
scroll_page_lines:
Scroll the screen varying amounts.
adjust_selection:
Adjust an existing selection in a given direction. This action
does nothing if there is no active selection.
jump_to_prompt:
Jump the viewport forward or back by prompt. Positive number is the
number of prompts to jump forward, negative is backwards.
write_scrollback_file:
Write the entire scrollback into a temporary file. The action
determines what to do with the filepath. Valid values are:
- "paste": Paste the file path into the terminal.
- "open": Open the file in the default OS editor for text files.
The default OS editor is determined by using `open` on macOS
and `xdg-open` on Linux.
write_screen_file:
Same as write_scrollback_file but writes the full screen contents.
See write_scrollback_file for available values.
write_selection_file:
Same as write_scrollback_file but writes the selected text.
If there is no selected text this does nothing (it doesn't
even create an empty file). See write_scrollback_file for
available values.
new_window:
Open a new window. If the application isn't currently focused,
this will bring it to the front.
new_tab:
Open a new tab.
previous_tab:
Go to the previous tab.
next_tab:
Go to the next tab.
last_tab:
Go to the last tab (the one with the highest index)
goto_tab:
Go to the tab with the specific number, 1-indexed. If the tab number
is higher than the number of tabs, this will go to the last tab.
move_tab:
Moves a tab by a relative offset.
Adjusts the tab position based on `offset`. For example `move_tab:-1` for left, `move_tab:1` for right.
If the new position is out of bounds, it wraps around cyclically within the tab range.
toggle_tab_overview:
Toggle the tab overview.
This only works with libadwaita enabled currently.
new_split:
Create a new split in the given direction. The new split will appear in
the direction given. For example `new_split:up`. Valid values are left, right, up, down and auto.
goto_split:
Focus on a split in a given direction. For example `goto_split:up`.
Valid values are left, right, up, down, previous and next.
toggle_split_zoom:
zoom/unzoom the current split.
resize_split:
Resize the current split by moving the split divider in the given
direction. For example `resize_split:left,10`. The valid directions are up, down, left and right.
equalize_splits:
Equalize all splits in the current window
inspector:
Show, hide, or toggle the terminal inspector for the currently focused
terminal.
open_config:
Open the configuration file in the default OS editor. If your default OS
editor isn't configured then this will fail. Currently, any failures to
open the configuration will show up only in the logs.
reload_config:
Reload the configuration. The exact meaning depends on the app runtime
in use but this usually involves re-reading the configuration file
and applying any changes. Note that not all changes can be applied at
runtime.
close_surface:
Close the current "surface", whether that is a window, tab, split, etc.
This only closes ONE surface. This will trigger close confirmation as
configured.
close_tab:
Close the current tab, regardless of how many splits there may be.
This will trigger close confirmation as configured.
close_window:
Close the window, regardless of how many tabs or splits there may be.
This will trigger close confirmation as configured.
close_all_windows:
Close all windows. This will trigger close confirmation as configured.
This only works for macOS currently.
toggle_fullscreen:
Toggle fullscreen mode of window.
toggle_window_decorations:
Toggle window decorations on and off. This only works on Linux.
toggle_secure_input:
Toggle secure input mode on or off. This is used to prevent apps
that monitor input from seeing what you type. This is useful for
entering passwords or other sensitive information.
This applies to the entire application, not just the focused
terminal. You must toggle it off to disable it, or quit Ghostty.
This only works on macOS, since this is a system API on macOS.
toggle_quick_terminal:
Toggle the "quick" terminal. The quick terminal is a terminal that
appears on demand from a keybinding, often sliding in from a screen
edge such as the top. This is useful for quick access to a terminal
without having to open a new window or tab.
When the quick terminal loses focus, it disappears. The terminal state
is preserved between appearances, so you can always press the keybinding
to bring it back up.
To enable the quick terminally globally so that Ghostty doesn't
have to be focused, prefix your keybind with `global`. Example:
\```ini
keybind = global:cmd+grave_accent=toggle_quick_terminal
\```
The quick terminal has some limitations:
- It is a singleton; only one instance can exist at a time.
- It does not support tabs, but it does support splits.
- It will not be restored when the application is restarted
(for systems that support window restoration).
- It supports fullscreen, but fullscreen will always be a non-native
fullscreen (macos-non-native-fullscreen = true). This only applies
to the quick terminal window. This is a requirement due to how
the quick terminal is rendered.
See the various configurations for the quick terminal in the
configuration file to customize its behavior.
This currently only works on macOS.
toggle_visibility:
Show/hide all windows. If all windows become shown, we also ensure
Ghostty becomes focused. When hiding all windows, focus is yielded
to the next application as determined by the OS.
This currently only works on macOS.
quit:
Quit ghostty.
crash:
Crash ghostty in the desired thread for the focused surface.
WARNING: This is a hard crash (panic) and data can be lost.
The purpose of this action is to test crash handling. For some
users, it may be useful to test crash reporting functionality in
order to determine if it all works as expected.
The value determines the crash location:
- "main" - crash on the main (GUI) thread.
- "io" - crash on the IO thread for the focused surface.
- "render" - crash on the render thread for the focused surface.
```
</details>
## Testing
- Run `ghostty-dev +list-actions --docs` to verify the new output format
- Check generated _zig-out/share/ghostty/webdata/actions.mdx_ to ensure
all actions are properly documented
Implements window position persistence on macOS, similar to Terminal.app
and iTerm2. The window position is saved when it becomes main or moves,
and restored on next startup. Window position is kept within visible
screen bounds.
cc @jsumners - Would you mind giving it a try? Any feedback would be
appreciated!
Resolves#4233
Fixes#5690
When we hide the app and then show it again, the previously key window
is lost. This is because we are not using unhide and are manually doing
it (and we're not using unhide for good reasons commented in the source
already).
Modify our hidden state to include what the key window was (as a weak
ref) and restore it when we show the app again.
Fully reset the kitty image storage instead of using the delete handler,
previously this caused a memory corruption / likely segfault due to use
of undefined, since the delete handler tries to clear the tracked pins
for placements, which it gets from the terminal, for which `undefined`
was passed in before.
Fixes#5690
When we hide the app and then show it again, the previously key window
is lost. This is because we are not using unhide and are manually
doing it (and we're not using unhide for good reasons commented in the
source already).
Modify our hidden state to include what the key window was (as a weak
ref) and restore it when we show the app again.
This fixes a regression from #5472. The fullscreen check must check if
the app is active otherwise the guard statement fails and we can't bring
the macOS app back from the background.
This regression never hit a versioned release, only tip.
This fixes a regression from #5472. The fullscreen check must check if
the app is active otherwise the guard statement fails and we can't bring
the macOS app back from the background.
This brings the internal package more in line with how the nixpkgs
package is built. It also handles recursive dependencies better than the
current system.
This brings the internal package more in line with how the nixpkgs
package is built. It also handles recursive dependencies better than the
current system.
Fixes#5635
### Changes:
- Added handling to `Screen.adjustCapacity` which properly returns an
error if there's no room for the cursor hyperlink. Note the TODO, in the
future we should probably make it handle this by increasing the capacity
further.
- Added handling to `Screen.cursorSetHyperlink` which ensures there will
be sufficient capacity to add the redundant cursor hyperlink to the
string alloc after adjusting the capacity.
***Future work:** Aside from separating the cursor's managed memory from
the page memory, which is a big thing we desperately need, we should
probably also make the page string alloc intern the strings it gets to
deduplicate.*
- Fixed a slight bug in the OSC parser which was causing the hyperlink
command to be issued with an empty (0-length) URI when the buffer
capacity was exceeded during an OSC 8 sequence.
***Future work:** We should consider increasing the `MAX_BUF` since some
specs call for a max size of 4096 (such as various Kitty protocols) --
otherwise we should switch all the OSCs that can take arbitrary data
like this to use the allocator instead of the fixed buffer.*
- Fixed a problem where when cloning content across pages (as happened
every time we had to adjust page capacities) hyperlinks would not be
properly looked up, often leading to many many redundant copies of a
given URI being stored, exploding string memory.
If a theme was not a file or a directory you could get a crash or a hang
(depending on platform) if the theme references a directory. This patch
also prevents attempts to load from other non-file sources.
Fixes: #5596
`zig-gobject` is a set of GObject bindings that allow us to write
GTK-facing code in Zig instead of getting hands dirty with C. It's been
tested and refined in real-life applications and several GTK
contributors agree that it is a marked improvement over using the C API
directly, such as allowing method call syntax and avoiding many manual
`@ptrCast`s.
This PR doesn't actually contain any changes to our preexisting GTK code
— the migration process is intended to begin in chunks, firstly in
self-contained components (e.g. the header bar, overlays, etc.), and
then full-scale migration can begin when we remove non-Adwaita GTK
builds for 1.2. (After all, why port code that you'll remove later
either way?)
`zig-gobject` is a set of GObject bindings that allow us to write
GTK-facing code in Zig instead of getting hands dirty with C.
It's been tested and refined in real-life applications and several
GTK contributors agree that it is a marked improvement over using
the C API directly, such as allowing method call syntax and avoiding
many manual `@ptrCast`s.
This commit doesn't actually contain any changes to our preexisting
GTK code — the migration process is intended to begin in chunks,
firstly in self-contained components (e.g. the header bar, overlays,
etc.), and then full-scale migration can begin when we remove non-Adwaita
GTK builds for 1.2. (After all, why port code that you'll remove later
either way?)
Previously assumed adjusted capacities would always fit the cursor style
and hyperlink, this is not necessarily the case and led to memory
corruption in scenarios with large hyperlinks.
I don't have a machine locally that can reproduce the issue in #5597 but
have been working with @paperlib over Discord to try to narrow down the
cause. My fix in #5625 didn't fix the problem, so I'm *really* hoping
this patch does.
The problem presents as any text that matches the default bg color not
being rendered, regardless of the cell's bg color. The best I can figure
is that either we have some sort of accidental UB or there's a driver
bug (perhaps related to the addition of the `[[flat]]` interpolation
qualifier to the vertex out structure?), but I don't have a system
locally to iterate on to narrow it down.
This optimization is extremely niche and seems to be related to a
strange bug experienced by Intel Mac users. Considering it costs some
amount to have this extra check here even though it's false in the vast
majority of cases, I feel it's pretty safe to just remove it entirely.
If a theme was not a file or a directory you could get a crash or a hang
(depending on platform) if the theme references a directory. This patch
also prevents attempts to load from other non-file sources.
Fixes: #5596
Discrete GPUs cannot use the "shared" storage mode. This causes
undefined behavior right now, and I believe it's what's causing a
problem on Intel systems with discrete GPUs with "inverted" cells.
(Observed in discussion #5597)
This commit also sets the CPU cache mode to "write combined" for our
resources since we don't read them back so Metal can optimize them
further with this hint.
Discrete GPUs cannot use the "shared" storage mode. This causes
undefined behavior right now, and I believe it's what's causing a
problem on Intel systems with discrete GPUs with "inverted" cells.
This commit also sets the CPU cache mode to "write combined" for our
resources since we don't read them back so Metal can optimize them
further with this hint.
This commit introduces the proposed subsystem maintainer system for
Ghostty. This commit doesn't assign anyone yet to the subsystems, but
defines the CODEOWNERS file, creates the GitHub teams, and documents the
system.
We can discuss this in Discord, but any feedback is also welcome here.
This commit introduces the proposed subsystem maintainer system for
Ghostty. This commit doesn't assign anyone yet to the subsystems, but
defines the CODEOWNERS file, creates the GitHub teams, and documents the
system.
When cursor color matches the background color, the optimization that
skips rendering identical colors causes the character under cursor to
become invisible. This PR ensures characters at cursor position are
always rendered, maintaining cursor visibility regardless of color
settings.
<img width="1129" alt="image"
src="https://github.com/user-attachments/assets/b82387c1-2bfd-481d-b679-1a1f82d21bcb"
/>
cc @kpovel - Would you mind giving it a try? Any feedback would be
appreciated!
Fixes#5554
This PR ensures visibility toggling is ignored when the currently
focused surface is fullscreen. This includes the following:
- Show/Hide All Terminals is ignored
- Using a binding to toggle is ignored
This ensures Ghostty doesn't unexpectedly lose focus or disappear and is
the expected behavior on macOS.
Fixes#5558
Binding checks would sometimes trigger preedit which would cause some
characters to leak through.
This is a bit of a band-aid. The real long term solution is noted in the
TODO comment in this commit, but I wanted to avoid regressions in a
patch release so I'm going to defer that to 1.2. This commit fixes the
main issue for 1.1.1.
Fixes#5558
Binding checks would sometimes trigger preedit which would cause some
characters to leak through.
This is a bit of a band-aid. The real long term solution is noted in the
TODO comment in this commit, but I wanted to avoid regressions in a
patch release so I'm going to defer that to 1.2. This commit fixes the
main issue for 1.1.1.
Fixes#5494
When ibus/fcitx is not running (the GTK "simple" input method is
active), the preedit end event triggers _before_ the commit event. For
both ibus/fcitx, the opposite is true. We were relying on this ordering.
This commit changes the GTK input handling to not rely on this ordering.
Instead, we encode our composing state into the boolean state of whether
a key event is pressed. This happens before ANY input method events are
triggered.
Tested dead key handling on: X11/Wayland, ibus/fcitx/none.
Fixes#5494
When ibus/fcitx is not running (the GTK "simple" input method is
active), the preedit end event triggers _before_ the commit event. For
both ibus/fcitx, the opposite is true. We were relying on this ordering.
This commit changes the GTK input handling to not rely on this ordering.
Instead, we encode our composing state into the boolean state of whether
a key event is pressed. This happens before ANY input method events are
triggered.
Tested dead key handling on: X11/Wayland, ibus/fcitx/none.
This is, admittedly, a very silly bug. On GNOME the SSD protocol is not
available and past me just decided to always enable CSDs in that case,
*even when* `window-decoration = none`. I now question my own
intelligence.
When trying to run valgrind this incorrectly results in a correct
result, this is because `posix.errno` will use libc errno when linking
libc which ghostty does.
cf90dfd309/lib/std/posix.zig (L219-L221)
Since we are making the syscall directly we should not use this function
but rather use the return code directly on the enum, name from this
function seems odd to me (no zig experience) but it is the suggested
answer from zig (refer to issue below)
https://github.com/ziglang/zig/issues/22718
Note this definitely isnt much better than what we were doing before in
the case of running in valgrind
```text
error(linux-cgroup): unable to clone: os.linux.E__enum_81093.NOSYS
debug(io_thread): IO thread exited
warning(io_thread): error in io thread err=error.CloneError
warning(io_thread): abrupt io thread exit detected, starting xev to drain mailbox
debug(io_thread): io thread fully exiting after abnormal failure
```
opening a new tab shows
```
error starting IO thread: error.CloneError
The underlying shell or command was unable to be started.
This error is usually due to exhausting a system resource.
If this looks like a bug, please report it.
This terminal is non-functional. Please close it and try again.
```
this did not show on the original surface only on the new tab
This is, admittedly, a very silly bug. On GNOME the SSD protocol is not
available and past me just decided to always enable CSDs in that case,
*even when* `window-decoration = none`. I now question my own intelligence.
Fixes#4218
This now requires a separate manually triggered `publish` workflow to be
run after the release completes in order to transition the release to
the `published` state.
Practically today this only means that the release will be published to
the macOS auto-updater, but in the future we could add additional steps
such as creating a GH release or some other notifications.
Importantly, this lets us verify the release in the uploaded location
before general users are notified of the update.
This now requires a separate manually triggered `publish` workflow to be
run after the release completes in order to transition the release to
the `published` state.
Practically today this only means that the release will be published to
the macOS auto-updater, but in the future we could add additional steps
such as creating a GH release or some other notifications.
Importantly, this lets us verify the release in the uploaded location
before general users are notified of the update.
Fixes#4522
This is a bit of a hammer-meets-nail solution, but it's a simple
solution to the problem. The reverse mapping is used to find the binding
that an action is bound to, and it's used by apprt's to populate the
accelerator label in the UI.
The problem is that accelerators in GTK are handled early in the event
handling process and its difficult to get that event mapping to a
specific surface. Therefore, the "performable" prefix was not working.
On macOS, this issue didn't exist because there exists an OS mechanism
to install an event handler earlier than the menu system.
This commit changes the reverse mapping to only include bindings that
are not performable. This way, the keybind always reaches the surface
and can be handled by `Surface.keyCallback` which processes
`performable`.
The caveat is that performable bindings will not show up in the UI for
menu items. This is documented in this commit now. They still work, its
just a UI issue.
Resolves#4730
I opted to link directly to the release notes of the updated version in
the `<description>` body, i.e. in the future it would link directly
v1.0.2's release notes at
https://ghostty.org/docs/install/release-notes/1-0-2. This thereby
implements the second option mentioned in the issue. It wasn't that much
harder than the third option, but if there's any particular reason _not
to_ link directly to a version's changelog page, I'll be more than happy
to modify this PR and implement the third option instead - in any case,
I had opened https://github.com/ghostty-org/website/pull/277 so that
https://ghostty.org/docs/install/release-notes is a valid page.
I also wrapped the current text `<![CDATA[ ... ]]>` just in case, as I
noticed this is a pretty standard practice in other apps that use
`<description>` to embed their release notes when using Sparkle -
[Sparkle's
documentation](https://sparkle-project.org/documentation/publishing/#embedded-release-notes)
says to do this so you can use unescaped HTML.
Fixes#4522
This is a bit of a hammer-meets-nail solution, but it's a simple
solution to the problem. The reverse mapping is used to find the
binding that an action is bound to, and it's used by apprt's to populate
the accelerator label in the UI.
The problem is that accelerators in GTK are handled early in the event
handling process and its difficult to get that event mapping to a
specific surface. Therefore, the "performable" prefix was not working.
On macOS, this issue didn't exist because there exists an OS mechanism
to install an event handler earlier than the menu system.
This commit changes the reverse mapping to only include bindings that
are not performable. This way, the keybind always reaches the surface
and can be handled by `Surface.keyCallback` which processes
`performable`.
The caveat is that performable bindings will not show up in the UI
for menu items. This is documented in this commit now. They still work,
its just a UI issue.
I found this bug was easily reproduced with any command that wrapped to
multiple rows on the first line of its output. The cause is that we stop
searching for rows once we reach the first one where
`row.semantic_prompt = .command`, which means that we reach the bottom
line of wrapped output and stop there.
This PR makes it so that we continue iterating until we reach a row
where `semantic_prompt != .command` and then return the previous one (or
the last one if we run out of rows).
I also updated the test cases to include this.
I considered that this bug would also be avoided if we didn't propagate
the `command` semantic prompt to additional rows on wrapped lines, but I
don't know enough about the shell integration to make a call on that.
Closes#4693
When setting up the GTK window with older Adwaita versions, we need to
explicitly create and add a tab bar. The previous code simply prepended
the tab bar into the GtkBox, which resulted in it being the very first
element (ahead of the title bar).
Instead, we grab a reference to the GTK title bar widget and call
`gtk_box_insert_child_after()` to explicitly insert our tab bar into the
hierarchy just after the title bar.
More mathematically sound approach, does a much better job of matching
the appearance of non-linear blending. Removed `experimental` from name
because it's not really an experiment anymore.
Related to #5361
The fix in 5361 wasn't sufficient since it only applied if our app was
in the foreground. Our quick terminal is a non-activating NSPanel to
allow it to work on any space (fullscreen included). This means that
Ghostty doesn't become the active app when the quick terminal is shown
and another app is in the foreground.
To work around this, we now hide the dock globally when the quick
terminal is shown AND the dock is in a conflicting position. We restore
this state when the quick terminal is hidden, loses focus, or Ghostty is
quit.
Related to #5361
The fix in 5361 wasn't sufficient since it only applied if our app was
in the foreground. Our quick terminal is a non-activating NSPanel to
allow it to work on any space (fullscreen included). This means that
Ghostty doesn't become the active app when the quick terminal is shown
and another app is in the foreground.
To work around this, we now hide the dock globally when the quick
terminal is shown AND the dock is in a conflicting position. We restore
this state when the quick terminal is hidden, loses focus, or Ghostty is
quit.
Related to #4446 , as suggested i've made a smaller chunk of updates for
the action binding docs, including arguments and examples. I did this
only for enum types this time.
I've also included the argument type name in the Argument (e.g.
AdjustSelection).
Not sure if we should include the keybindings or not in the example?
I also added a format of some unrelated code change.
Print chorded/sequenced keybinds in `+list-keybinds`.
Recursively traverses the binding sets of sequenced keybinds and builds
a singly-linked list of triggers for each leaf. Also adapted the current
sorting criteria to work for multiple triggers per keybind.
Chorded keybinds are already output when not printing to a tty so that
code path is unchanged.
Closes#4505
Fixes#5328
The dock sits above the level of the quick terminal, and the quick
terminal frame typical includes the dock. Hence, if the dock is visible
and the quick terminal would conflict with it, then part of the terminal
is obscured.
This commit makes the dock autohide if the quick terminal would conflict
with it. The autohide is disabled when the quick terminal is closed.
We can't set our window level above the dock, as this would prevent
things such as input methods from rendering properly in the quick
terminal window.
iTerm2 (the only other macOS terminal I know of that supports a dropdown
mode) frames the terminal around the dock. I think this looks less
aesthetically pleasing and I prefer autohiding the dock instead.
We can introduce a setting to change this behavior if desired later.
Additionally, this commit introduces a mechanism to safely set
app-global presentation options from multiple sources without stepping
on each other.
## Demo
https://github.com/user-attachments/assets/1f5bb945-dca4-49e7-8bcb-95b55524cfb5
Fixes#5328
The dock sits above the level of the quick terminal, and the quick
terminal frame typical includes the dock. Hence, if the dock is visible
and the quick terminal would conflict with it, then part of the terminal
is obscured.
This commit makes the dock autohide if the quick terminal would conflict
with it. The autohide is disabled when the quick terminal is closed.
We can't set our window level above the dock, as this would prevent
things such as input methods from rendering properly in the quick
terminal window.
iTerm2 (the only other macOS terminal I know of that supports a dropdown
mode) frames the terminal around the dock. I think this looks less
aesthetically pleasing and I prefer autohiding the dock instead.
We can introduce a setting to change this behavior if desired later.
Additionally, this commit introduces a mechanism to safely set
app-global presentation options from multiple sources without stepping
on each other.
Fixes#5359
The comments explain what's going on. Longer term we should adjust our
termio/exec to avoid the SIGPIPE but its still possible (i.e. that
thread crashes) to happen so we should be robust to it.
Fixes#5359
The comments explain what's going on. Longer term we should adjust our
termio/exec to avoid the SIGPIPE but its still possible (i.e. that
thread crashes) to happen so we should be robust to it.
Fixes#5253
Add -Demit-terminfo and -Demit-termcap build options to enable/disable
installation of source terminfo and termcap files.
Replacement for #5311
Fixes#4554
When a process exited on its own (we didn't kill it), we were not
calling waitpid. This commit adds a waitpid call in the event loop
process exit notification.
This happened because when an external exit happened we could call
`subprocess.externalExit` which tells our subprocess manager to NOT kill
the process (since its already dead). Unfortunately in this case it
means we also didn't call waitpid.
Fixes#4554
xev.Process.wait is documented as being equivalent to calling `waitpid`,
i.e. including reaping the process. On Linux, it does this automatically
by using pidfd and the `waitid` syscall. On macOS, it wasn't doing this.
This commit updates libxev to include a fix that explicitly calls
`waitpid` for kqueue.
Fixes#4884
When our command exits, it will close the pty slave fd. This will
trigger a HUP on our poll. Previously, we only checked for IN. When a fd
is closed, IN triggers forever which would leave to an infinite loop and
100% CPU.
Now, detect the HUP and exit the read thread.
Fixes#4884
When our command exits, it will close the pty slave fd. This will
trigger a HUP on our poll. Previously, we only checked for IN. When a fd
is closed, IN triggers forever which would leave to an infinite loop and
100% CPU.
Now, detect the HUP and exit the read thread.
Multiple fixes to prevent file descriptor leaks:
- libxev eventfd now uses CLOEXEC
- linux: cgroup clone now uses CLOEXEC for the cgroup fd
- termio pipe uses pipe2 with CLOEXEC
- pty master always sets CLOEXEC because the child doesn't need it
- termio exec now closes pty slave fd after fork
There still appear to be some fd leaks happening. They seem related to
GTK, they aren't things we're accessig directly. I still want to
investigate them but this at least cleans up the major sources of fd
leakage.
Multiple fixes to prevent file descriptor leaks:
- libxev eventfd now uses CLOEXEC
- linux: cgroup clone now uses CLOEXEC for the cgroup fd
- termio pipe uses pipe2 with CLOEXEC
- pty master always sets CLOEXEC because the child doesn't need it
- termio exec now closes pty slave fd after fork
There still appear to be some fd leaks happening. They seem related to
GTK, they aren't things we're accessig directly. I still want to
investigate them but this at least cleans up the major sources of fd
leakage.
This fixes a regression introduced by the rework of this area before
during the color space changes (#4913). It seems like the original
intent of this code was the behavior it regressed to, but it turns out
to be better like this.
This fixes a regression introduced by the rework of this area before
during the color space changes. It seems like the original intent of
this code was the behavior it regressed to, but it turns out to be
better like this.
## Description
Fixed an issue where hyperlinks would maintain their hover state when
the mouse is outside the viewport while holding the Cmd key. This
created inconsistent behavior with the window's standard hover state
clearing logic.
## Changes
- Added viewport boundary check in `mouseRefreshLinks` function to
prevent link processing when cursor is outside the window
## Testing
To reproduce and verify the fix:
1. Run `fd --hyperlink "\.zig$" src/apprt` to create hyperlinks
2. Move mouse over a hyperlink (it should highlight)
3. Move mouse outside window
4. Hold Cmd key
- Before: Link would show hover state
- After: Link remains in non-hover state
Fixes#5252
@rrotter Could you please try this to see if it solves your issue?
A '-' or '--' argument signals the end of bash's own options. All
remaining arguments are treated as filenames and arguments. We shouldn't
perform any additional argument processing once we see this signal.
We could also assume a non-interactive shell session in this case unless
the '-i' (interactive) shell option has been explicitly specified, but
let's wait on that until we know that doing so would solve a real user
problem (and avoid any false negatives).
Currently, `sudo_has_sudoedit_flags` variable is being erased when `for`
block ends.
Change its scope to `--function` to prevent this.
Fixes `sudo: you may not specify environment variables in edit mode`.
Duplicate existing reference docs generation to cover cli actions. Docs
update pass to make the structure consistent.
See https://github.com/ghostty-org/website/pull/253 for website changes.
Adds a Nix VM configuration to run Gnome/Wayland. The primary purpose
will be testing Ghostty in a "clean" environment. I'm going to continue
to experiment with running this in CI to see if we can do some basic
testing of GTK since it's difficult to unit test that code.
To use, run `nix run .#wayland-gnome` in the Ghostty source directory. I
have no idea if this works on macOS. There's probably a lot of extra
stuff that can be trimmed to slim it down.
Whatever directory you run this from will be mounted at `/tmp/shared` in
the VM. The `ghostty` user runs as uid/gid 1000/1000 so that may affect
your ability to read/write that directory if your host system user runs
as a different uid/gid.
If this is something that we'd like to keep, we should add VM
definitions for KDE Plasma and maybe one tiling window manager.
https://github.com/user-attachments/assets/57190913-f338-4383-93aa-90c9e351543d
Requesting the initial color scheme on systems where the D-Bus interface
is nonexistent would delay Ghostty startup by 1-2 minutes. That's not
acceptable. Our color scheme events are already async-friendly anyway.
Fixes#4632
Requesting the initial color scheme on systems where the D-Bus interface
is nonexistent would delay Ghostty startup by 1-2 minutes. That's not
acceptable. Our color scheme events are already async-friendly anyway.
Fixes#4632
Fixes#4631
This introduces a mechanism by which parsed config fields can be renamed
to maintain backwards compatibility. This already has a use case --
implemented in this commit -- for `background-blur-radius` to be renamed
to `background-blur`.
The remapping is comptime-known which lets us do some comptime
validation. The remap check isn't done unless no fields match which
means for well-formed config files, there's no overhead.
For future improvements:
- We should update our config help generator to note renamed fields.
- We could offer automatic migration of config files be rewriting them.
- We can enrich the value type with more metadata to help with config
gen or other tooling.
Fixes#4631
This introduces a mechanism by which parsed config fields can be renamed
to maintain backwards compatibility. This already has a use case --
implemented in this commit -- for `background-blur-radius` to be renamed
to `background-blur`.
The remapping is comptime-known which lets us do some comptime
validation. The remap check isn't done unless no fields match which
means for well-formed config files, there's no overhead.
For future improvements:
- We should update our config help generator to note renamed fields.
- We could offer automatic migration of config files be rewriting them.
- We can enrich the value type with more metadata to help with
config gen or other tooling.
Currently `macos-titlebar-style = hidden` doesn't prevent the native
window drag gesture in the top region of the window- in the original PR
it did, but there were issues with how it went about it so it was
removed (see c6bbdfb). I figured out how to safely and simply remove the
gesture, and as a bonus it opens up potential future enhancements.
The native window drag region is driven ultimately by the window's
`contentLayoutRect`, so we can just override it in `TerminalWindow` to
return a rect the size of the full window, disabling the gesture without
causing any side effects by altering the responder chain.
This makes `macos-titlebar-style = hidden` a much nicer experience. The
window can still be resized, managed by the OS and third party window
managers, and dragged by the edges, but the native drag gesture in the
titlebar region is fully avoided.
### Future work
We may consider adjusting this to produce a `contentLayoutRect` that
doesn't include the padding area of the terminal grid(s), so that the
window can be dragged from a larger region around the edges (and not
just the resize region).
The native window drag region is driven ultimately by the window's
`contentLayoutRect`, so we can just override it in `TerminalWindow`
to return a rect the size of the full window, disabling the gesture
without causing any side effects by altering the responder chain.
NEEDS REVIEW
continuation of #5037resolves#4729
renders all shaders to the default buffer and then copies it to the
designated custom shader texture.
this is a draft pr because:
- it introduces a new shader "pipeline" which doesnt fit in with how the
system was designed to work (which is only rendering to the fbo)
- im not sure if this is the best way to achieve shaders being able to
sample their output while also drawing to the screen. the cusom fbo
(previous implementation) was useful in that it modularized the custom
shader stage in rendering
---------
Co-authored-by: Mitchell Hashimoto <m@mitchellh.com>
Fixes#3567
ibus 1.5.29 doesn't trigger a preedit end state when text is committed.
This is fixed in ibus 1.5.30, but we need to handle this case for older
versions which are shipped on LTS distributions such as Ubuntu.
Every other input method engine I've tried thus far also triggers a
preedit end state when text is committed, and none would expect preedit
to continue after text is committed. So I think it's safe to assume that
this is the expected behavior.
Fixes#3567
ibus 1.5.29 doesn't trigger a preedit end state when text is committed.
This is fixed in ibus 1.5.30, but we need to handle this case for older
versions which are shipped on LTS distributions such as Ubuntu.
Every other input method engine I've tried thus far also triggers a
preedit end state when text is committed, and none would expect preedit
to continue after text is committed. So I think it's safe to assume that
this is the expected behavior.
A '-' or '--' argument signals the end of bash's own options. All
remaining arguments are treated as filenames and arguments. We shouldn't
perform any additional argument processing once we see this signal.
We could also assume a non-interactive shell session in this case unless
the '-i' (interactive) shell option has been explicitly specified, but
let's wait on that until we know that doing so would solve a real user
problem (and avoid any false negatives).
Related to #3567
This cleans up our handling of when GTK tells us the input method
handled the key press to address more scenarios we should not encode the
key event. The comments in this diff should explain clearly.
Reproduction is simple:
1. Use ibus (X11 or Wayland doesn't matter)
2. Press `super+.` to activate the emoji keyboard
3. Notice the `.` is written to the shell AND the emoji keyboard is
activated.
The bug is that `.` should not be encoded since it was used to activate
the emoji keyboard. This PR fixes that.
This cleans up our handling of when GTK tells us the input method
handled the key press to address more scenarios we should not encode the
key event. The comments in this diff should explain clearly.
Fixes#4332
This commit fundamentally reworks the input method handling in the GTK
apprt, making it work properly (as reported in the linked issue) on both
Wayland and X11. This was tested with both a Gnome desktop on Wayland
and i3 on X11 with fcitx and mozc.
The main changes are:
- Both key press and release events must be forwarded to the input
method.
- Input method callbacks such as preedit and commit must be expected
outside of keypress events to handle on-screen keyboards and
non-keyboard input devices.
- Input methods should always commit when told to. Previously, we would
only commit when a keypress event was given. This is incorrect. For
example, it didn't work with input method changes outside the app which
should result in committed text (as can be seen with "official" Gnome
apps like Notes or Console).
The key input handling also now generally does less so I think input
latency should be positively affected by this change. I didn't measure.
Fixes#4332
This commit fundamentally reworks the input method handling in the GTK
apprt, making it work properly (as reported in the linked issue) on both
Wayland and X11. This was tested with both a Gnome desktop on Wayland
and i3 on X11 with fcitx and mozc.
The main changes are:
- Both key press and release events must be forwarded to the input
method.
- Input method callbacks such as preedit and commit must be expected
outside of keypress events to handle on-screen keyboards and
non-keyboard input devices.
- Input methods should always commit when told to. Previously, we would
only commit when a keypress event was given. This is incorrect. For
example, it didn't work with input method changes outside the app
which should result in committed text (as can be seen with "official"
Gnome apps like Notes or Console).
The key input handling also now generally does less so I think input
latency should be positively affected by this change. I didn't measure.
Resolves#4523
More notably this fixes a memory corruption crash that can occur while
resizing the font under Metal while there's a lot of active changes
occurring (e.g. while running DOOM fire). The change where all
background colors are explicitly written exposed this issue, though it
was technically a problem the whole time I'm fairly sure, just that the
corruption it caused before was benign.
This significantly improves the robustness of the renderers since it
prevents synchronization issues from causing memory corruption due to
out of bounds read/writes while building the cells.
TODO: when viewport is narrower than renderer grid size, fill blank
margin with bg color- currently appears as black, this only affects
DECCOLM right now, and possibly could create single-frame artefacts
during poorly managed resizes, but it's not ideal regardless.
This significantly improves the robustness of the renderers since it
prevents synchronization issues from causing memory corruption due to
out of bounds read/writes while building the cells.
TODO: when viewport is narrower than renderer grid size, fill blank
margin with bg color- currently appears as black, this only affects
DECCOLM right now, and possibly could create single-frame artefacts
during poorly managed resizes, but it's not ideal regardless.
#4033 introduced a `ctrl-shift-w` binding to close a tab, but it doesn't
respect the `confirm-close-surface` option. Now `ctrl-shift-w` will ask
for confirmation exactly the same as clicking the close button with the
mouse.
fixes#4729
allows the shaders to sample each other via the fbo texture.
also, a better example would use the full screen e.g.:
"behind.glsl"
```glsl
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
fragColor = vec4(fragCoord/iResolution.xy, 0.0, 1.0);
}
```
"infront.glsl"
```glsl
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
fragColor = texture(iChannel0, fragCoord/iResolution.xy);
}
```
`ghostty --custom-shader=behind.glsl --custom-shader=infront.glsl`
|before|after|
|-|-|
|

|
|
Fixes core issue #4957. Adds a bool to `SelectLine` allowing the
`selectLine` function to select lines that are empty. When starting a
triple selection on an empty line the initial `selectLine` returns null
because we don't see any characters, in this case we rerun `selectLine`
but short circuit with the `allow_empty_lines`. We need to run
`selectLine` with out allowing empty lines once because if there are
characters on the line we don't want to select empty space.
Resolves#5108
Reproduction: While Stage Manager is activated, create a new tab in
Ghostty, run `sleep 500` in that tab, and try and close it. Make sure to
try both closing the tab with cmd-w and clicking the x; also try
accepting the modal with a mouse click and pressing enter.
Relevant AppKit documentation: [NSAlert
beginSheetModal](https://developer.apple.com/documentation/appkit/nsalert/beginsheetmodal(for:completionhandler:))
What I believe is happening is that the alert modal ("there is still a
process running") is closed automatically after the completion handler
is run, which closes the window on which the alert is attached.
Something seems to go wrong in Stage Manager at this point; perhaps it
detects the alert closing as a "full" window closing and moves focus to
a different window.
The fix I've identified is to manually call the `orderOut` function to
dismiss the alert _before_ the code that closes the window is run.
## Descriptions
The code was short-circuiting the shell integration setup when
`shell-integration = none`, which prevented the feature environment
variables from being set. These environment variables are needed even
for manual shell integration to work properly.
## Changes
- Extracted feature environment variables setup into a separate
`setup_features` function
- Modified the shell integration initialization to ensure features are
set up even when `shell-integration = none`
<img width="1126" alt="image"
src="https://github.com/user-attachments/assets/ceeb33f5-26ee-4a3b-a6d5-eed57848c96c"
/>
Fixes https://github.com/ghostty-org/ghostty/issues/5046
The variant format string `^aay` is said to be equivalent to
`g_variant_new_bytestring_array`. Given that no length parameter is
provided, glib assumed a null-terminated array, causing a crash as glib
exceed the read boundaries to copy arbitrary memory.
This commit replaces the array construction code to use its arena
equivalents instead of glib, and make sure that the resulting array is
null-terminated.
Fixes#3616.
This was causing excessively faint/dark areas anywhere there was
transparency, since our image shaders for both Metal and OpenGL assume
the image data has straight alpha (which, I think should be the case for
data transmitted directly with kitty graphics protocol rather than
png-encoded), and do an additional multiplication.
After this change, our image blending looks *like most other apps*, even
though it's still technically wrong since it "should" be done in linear
space. Kitty, for example, does do linear blending for images, which is
*more correct* even though it doesn't look like most apps. On macOS if
`text-blending` is set to `linear` we do get linear blending, and match
Kitty exactly with this change.
In order to have linear blending of images while maintaining non-linear
blending of text for a "native" look on macOS we'd have to use swap
textures with different pixel formats (`*_srgb` / not `*_srgb`) or else
the API validator yells at us (even though it *does* work correctly...)
-- either that or perform our blending in a shader instead of relying on
Metal, which is my plan ultimately whenever I get around to making the
deferred render pipeline.
login(1)'s .hushlogin logic was "fixed" in macOS Sonoma 14.4, so this
comment (and our workaround) is only relevant for versions earlier than
that.
The relevant change to login/login.c is part of system_cmds-979.100.8.
> login.c: look for .hushlogin in home directory (112854361)
-
1bca46ecc5
-
https://github.com/apple-oss-distributions/distribution-macOS/tree/macos-144
The intention of #5075 was to create a less intrusive, more hermetic
environment in which to source the bash startup files. This caused
problems for multiple people, and I believe that's because the general
expectation is that these files are sourced at global (not function)
scope.
For example, when a file is sourced from within a function scope, any
variables that weren't explicitly exported into the global environment
won't be available outside of the scope of the function. Most system and
personal startup files aren't written with that constraint because it's
not how bash itself loads these files.
As a small improvement over the original code, `rcfile` has been renamed
to `__ghostty_rcfile`. Avoiding leaking this variable while sourcing
these files was a goal of #5075, and prefixing it make it much less of a
potential issue.
This change also reverts the $HOME -> ~/ change. While the ~/ notation
is more concise, using $HOME is more common and easier to implement
safely with regard to quoting.
Fixes#5206
The intention of #5075 was to create a less intrusive, more hermetic
environment in which to source the bash startup files. This caused
problems for multiple people, and I believe that's because the general
expectation is that these files are sourced at global (not function)
scope.
For example, when a file is sourced from within a function scope, any
variables that weren't explicitly exported into the global environment
won't be available outside of the scope of the function. Most system and
personal startup files aren't written with that constraint because it's
not how bash itself loads these files.
As a small improvement over the original code, `rcfile` has been renamed
to `__ghostty_rcfile`. Avoiding leaking this variable while sourcing
these files was a goal of #5075, and prefixing it make it much less of a
potential issue.
This change also reverts the $HOME to ~/ change. While the ~/ notation
is more concise, using $HOME is more common and easier to implement
safely with regard to quoting.
ghostty#5000 changed the window level from `.popupMenu` to `.floating`
to improve IME support. However, this introduced a side effect which
render the Quick Terminal (QT) below the macOS menu bar, whereas
previously it would cover it.
When positioned on `right` and `left`, the top of the QT becomes
partially hidden. This PR adjust the size of the QT to ensure it remains
fully visible and stays below the menu bar.
login(1)'s .hushlogin logic was "fixed" in macOS Sonoma 14.4, so this
comment (and our workaround) is only relevant for versions earlier than
that.
The relevant change to login/login.c is part of system_cmds-979.100.8.
> login.c: look for .hushlogin in home directory (112854361)
- 1bca46ecc5
- https://github.com/apple-oss-distributions/distribution-macOS/tree/macos-144
The variant format string `^aay` is said to be equivalent to
g_variant_new_bytestring_array. Given that no length parameter is
provided, g_variant_new assumed a null-terminated array, but the array
constructed by the code was not, causing a crash as glib exceed the read
boundaries to copy arbitrary memory.
This commit replaces the array construction code to use its arena
equivalents instead of trying to build one using glib, and make sure
that the resulting array is null-terminated.
This commit fixes two issues with the `list-actions` command:
1. Ensures all actions are listed, including those without individual
documentation but sharing docs with related actions
2. Improves documentation formatting with proper indentation and grouping
Previously, `ghostty +list-actions` would only show actions that had doc
comments, making it difficult for users to discover all available actions.
This change ensures all actions are listed with appropriate documentation.
For actions without doc comments, we now generate a default message
encouraging contribution.
It seems like the raw data version of the kitty graphics transmit
operation is meant to be unassociated (aka straight) alpha, though I
can't find any definitive documentation either way- but in any case
unassociated alpha is more common in image formats and makes the
handling easier for the rest of it.
Also removed a redundant call to `decode_frame_config`, since it's
called implicitly when we call `decode_frame` right after.
`load_color` was multiplying the alpha channel by itself as well, rather
than just the `rgb` channels.
Also made sure to divide alpha out before applying gamma encoding back
to text color when not using linear blending, which was another source
of error.
Probably fixes the problem observed in #5133 -- I couldn't reproduce the
exact color shift, but did see a similar one with some of my test
colors. This most visibly affects dimmed text since it uses an alpha of
less than 1 for the text color.
Allowing the alert to be automatically closed after the completion handler finishes doesn't seem to play well when the completion handler closes the window on which the alert is attached
We use `trap` to bootstrap our installation function (__bp_install). We
remove our code upon first execution but need to restore any preexisting
trap calls. We previously used `sed` to process the trap string, but
that had two downsides:
1. `sed` is an external command dependency. It needs to exist on the
system, and we need to invoke it in a subshell (which has some runtime
cost).
2. The regular expression pattern was imperfect and didn't handle
trickier cases like `'` characters in the trap string:
$ (trap "echo 'hello'" DEBUG; trap -p DEBUG)
hello
trap -- 'echo '\''hello'\''' DEBUG
This change removes the dependency on `sed` by locally evaluating the
trap string and extracting any prior trap. This works reliably because
we control the format our trap string, which looks like this (with
newlines expanded):
__bp_trap_string="$(trap -p DEBUG)"
trap - DEBUG
__bp_install
Upstream: https://github.com/rcaloras/bash-preexec/pull/170
We post-process history 1's output to extract the current command. This
processing needs to strip the leading history number, an optional *
character indicating whether the entry was modified (or a space), and
then a space separating character.
We were previously using sed(1) for this, but we can implement an
equivalent transformation using bash's native parameter expansion
syntax.
This also results in ~4x reduction in per-prompt command overhead.
Upstream: https://github.com/rcaloras/bash-preexec/pull/167
We now use a temporary function (__ghostty_bash_startup) to perform the
bash startup sequence. This gives us a local function scope in which to
store some temporary values (like rcfile). This way, they won't leak
into the sourced files' scopes.
Also, use `~/` instead of `$HOME` for home directory paths as a simpler
shorthand notation.
Compositors can actually tell us whether they want to use CSD or SSD!
(Ignore the context menu changes — they will most likely be unified
after #4952 anyway)
We were returning bg colors when we shouldn't have since when we have
background color transparency we need to return any bg color cells as
fully transparent rather than their actual color.
This caused a problem of overly opaque padding when background opacity
was < 1.0
We use `trap` to bootstrap our installation function (__bp_install). We
remove our code upon first execution but need to restore any preexisting
trap calls. We previously used `sed` to process the trap string, but
that had two downsides:
1. `sed` is an external command dependency. It needs to exist on the
system, and we need to invoke it in a subshell (which has some
runtime cost).
2. The regular expression pattern was imperfect and didn't handle
trickier cases like `'` characters in the trap string:
$ (trap "echo 'hello'" DEBUG; trap -p DEBUG)
hello
trap -- 'echo '\''hello'\''' DEBUG
This change removes the dependency on `sed` by locally evaluating the
trap string and extracting any prior trap. This works reliably because
we control the format our trap string, which looks like this (with
newlines expanded):
__bp_trap_string="$(trap -p DEBUG)"
trap - DEBUG
__bp_install
We post-process history 1's output to extract the current command. This
processing needs to strip the leading history number, an optional *
character indicating whether the entry was modified (or a space), and
then a space separating character.
We were previously using sed(1) for this, but we can implement an
equivalent transformation using bash's native parameter expansion
syntax.
This also results in ~4x reduction in per-prompt command overhead.
We now use a temporary function (__ghostty_bash_startup) to perform the
bash startup sequence. This gives us a local function scope in which to
store some temporary values (like rcfile). This way, they won't leak
into the sourced files' scopes.
Also, use `~/` instead of `$HOME` for home directory paths as a simpler
shorthand notation.
We were returning bg colors when we shouldn't have since when we have
background color transparency we need to return any bg color cells as
fully transparent rather than their actual color.
Fixes#4516
By using the `CAMetalLayer`'s `backgroundColor` property instead of
drawing the background color in our shader, it is always stretched to
cover the full surface, even when live-resizing, and it doesn't require
us to draw a frame for it to be initialized so there's no transparent
flash when a new surface is created (as in a new split/tab).
This commit also allows for hot reload of `background-opacity`,
`window-vsync`, and `window-colorspace`.
By using the `CAMetalLayer`'s `backgroundColor` property instead of
drawing the background color in our shader, it is always stretched to
cover the full surface, even when live-resizing, and it doesn't require
us to draw a frame for it to be initialized so there's no transparent
flash when a new surface is created (as in a new split/tab).
This commit also allows for hot reload of `background-opacity`,
`window-vsync`, and `window-colorspace`.
3cdb9a7 made ghostty unable to compile on my debian system (adwaita
1.2.2) due to `adw_tab_overview_set_show_start_title_buttons` and
`adw_tab_overview_set_show_end_title_buttons` which are since 1.3.0. I
increased the comptime check to 1.4.0, this is fine since the assignment
of `tab_overview` is [already comptime guarded by
1.4.0](3cdb9a7dfe/src/apprt/gtk/Window.zig (L130))
This PR addresses #2125 for the Metal renderer. Both options are
available: "Apple-style" blending where colors are blended in a wide
gamut color space, which reduces but does not eliminate artifacts; and
linear blending where colors are blended in linear RGB.
Because this doesn't add support for linear blending on Linux, I don't
know whether the issue should be closed or not.
### List of changes in no particular order
- We now set the layer's color space in the renderer not in the apprt
- We always set the layer to Display P3 color spaces
- If the user hasn't configured their `window-colorspace` to
`display-p3` then terminal colors are automatically converted from sRGB
to the corresponding Display P3 color in the shader
- Background color is not set with the clear color anymore, instead we
explicitly set all bg cell colors since this is needed for minimum
contrast to not break with dark text on the default bg color (try it
out, it forces it fully white right now), and we just draw the
background as a part of the bg cells shader. Note: We may want to move
the main background color to be the `backgroundColor` property on the
`CAMetalLayer`, because this should fix the flash of transparency during
startup (#4516) and the weirdness at the edge of the window when
resizing. I didn't make that a part of this PR because it requires
further changes and my changes are already pretty significant, but I can
make it a follow-up.
- Added a config option for changing alpha blending between "native"
blending, where colors are just blended directly in sRGB (or Display P3)
and linear blending, where colors are blended in linear space.
- Added a config option for an experimental technique that I think works
pretty well which compensates for the perceptual thinning and thickening
of dark and light text respectively when using linear blending.
- Custom shaders can now be hot reloaded with config reloads.
- Fixed a bug that was revealed when I changed how we handle
backgrounds, page widths weren't being set while cloning the screen.
### Main takeaways
Color blending now matches nearly identically to Apple apps like
Terminal.app and TextEdit, not *quite* identical in worst case
scenarios, off by the tiniest bit, because the default color space is
*slightly* different than Display P3.
Linear alpha blending is now available for mac users who prefer more
accurate color reproduction, and personally I think it looks very nice
with the alpha correction turned on, I will be daily driving that
configuration.
### Future work
- Handle primary background color with `CALayer.backgroundColor` instead
of in shader, to avoid issues around edges when resizing.
- Parse color space info directly from ICC profiles and compute the
color conversion matrix dynamically, and pass it as a uniform to the
shaders.
- Port linear blending option to OpenGL.
- Maybe support wide gamut images (right now all images are assumed to
be sRGB).
This commit is quite large because it's fairly interconnected and can't
be split up in a logical way. The main part of this commit is that alpha
blending is now always done in the Display P3 color space, and depending
on the configured `window-colorspace` colors will be converted from sRGB
or assumed to already be Display P3 colors. In addition, a config option
`text-blending` has been added which allows the user to configure linear
blending (AKA "gamma correction"). Linear alpha blending also applies to
images and makes custom shaders receive linear colors rather than sRGB.
In addition, an experimental option has been added which corrects linear
blending's tendency to make dark text look too thin and bright text look
too thick. Essentially it's a correction curve on the alpha channel that
depends on the luminance of the glyph being drawn.
As recommended in
https://github.com/ghostty-org/ghostty/pull/4927#issuecomment-2585003934,
adds a config option `maximize` for starting a window in a maximized
state in terms of window properties. Also adds a `toggle_maximize`
keybind to allow users to manually toggle this feature on and off.
It might make more sense to make this an optional config value so that
we don't toggle the state off if the WM already handles that for us, but
I'll let a reviewer decide.
Closes https://github.com/ghostty-org/ghostty/issues/4646
Previously, the logic navigated to the second-to-last tab instead of the
last tab due to an off-by-one error. This updates the implementation so
that the index calculation to accurately target the last tab. In the
`gotoLastTab` method there was a decrement in the number of max number
of tabs and another increment in the `goToTab` method to get the actual
tab index.
## Description
When pasting URLs from clipboard, the behavior varies based on the
source:
1. From browser address bar:
- Pasteboard types: ["public.utf8-plain-text", "NSStringPboardType"]
- Handled as plain text, resulting in correct full URL paste
2. From clipboard history tools, such as Raycast clipboard history:
- Pasteboard types include "public.url" and related URL types
- URL was being processed through NSURL, which only extracted the path
component
- This resulted in incomplete URLs
## Changes
- Modified `getOpinionatedStringContents()` to differentiate URL types:
- For file URLs (`file://`): preserve existing behavior, return path
only
- For web URLs (`http://`, `https://`): return full URL string via
`absoluteString`
- For non-URL content: maintain existing plain text handling
## Related Issues
Fixes#5026
@caarlos0 Could you please help check if this resolves the issue you
were encountering?
Fixes#5022
The CSI SGR sequence (CSI m) is unique in that its the only CSI sequence
that allows colons as delimiters between some parameters, and the colon
vs. semicolon changes the semantics of the parameters.
Previously, Ghostty assumed that an SGR sequence was either all colons
or all semicolons, and would change its behavior based on the first
delimiter it encountered.
This is incorrect. It is perfectly valid for an SGR sequence to have
both colons and semicolons as delimiters. For example, Kakoune sends the
following:
;4:3;38;2;175;175;215;58:2::190:80:70m
This is equivalent to:
- unset (0)
- curly underline (4:3)
- foreground color (38;2;175;175;215)
- underline color (58:2::190:80:70)
This commit changes the behavior of Ghostty to track the delimiter per
parameter, rather than per sequence. It also updates the SGR parser to
be more robust and handle the various edge cases that can occur. Tests
were added for the new cases.
Fixes#5022
The CSI SGR sequence (CSI m) is unique in that its the only CSI sequence
that allows colons as delimiters between some parameters, and the colon
vs. semicolon changes the semantics of the parameters.
Previously, Ghostty assumed that an SGR sequence was either all colons
or all semicolons, and would change its behavior based on the first
delimiter it encountered.
This is incorrect. It is perfectly valid for an SGR sequence to have
both colons and semicolons as delimiters. For example, Kakoune sends
the following:
;4:3;38;2;175;175;215;58:2::190:80:70m
This is equivalent to:
- unset (0)
- curly underline (4:3)
- foreground color (38;2;175;175;215)
- underline color (58:2::190:80:70)
This commit changes the behavior of Ghostty to track the delimiter per
parameter, rather than per sequence. It also updates the SGR parser to
be more robust and handle the various edge cases that can occur. Tests
were added for the new cases.
Previously, the logic navigated to the second-to-last tab instead of the
last tab due to an off-by-one error. This updates the implementation so
that the index calculation to accurately target the last tab.
In the `gotoLastTab` method there was a decrement in the number of max
number of tabs and another increment in the `goToTab` method to get the
actual tab index.
Fixes#4999
We need to set the level to popUpMenu so that we can move the window
offscreen and animate it over the main menu, but we must reset it back
to floating after the animation is complete so that other higher-level
windows can be shown on top of it such as IME windows.
Fixes#4999
We need to set the level to popUpMenu so that we can move the window
offscreen and animate it over the main menu, but we must reset it back
to floating after the animation is complete so that other higher-level
windows can be shown on top of it such as IME windows.
Fixes#3345
Piggybacking on the logic introduced PR
https://github.com/ghostty-org/ghostty/pull/3997, this patch prevents
mouse motion events with the same cursor position triggered by the
window title updating from un-hiding the mouse even when
`mouse-hide-while-typing` config item is true.
Ghostty with libadwaita older than 1.4.0 (in my case, that of debian
bookworm) will segfault when you exit ghostty with ctrl+d. This was
already fixed by #3694 but it re-appeared during a refactor. The fix
simply uses a reference to `tab.window.window` to call
`gtk_window_destroy`, because `tab.window` has already been [destroyed
by a signal
handler](6cbd69da78/src/apprt/gtk/Tab.zig (L130-L137))
triggered in the old libadwaita path.
Original issue: #3135
This PR ensures one can drag and drop the following things to the
terminal window:
- File (Inserts the file path into the terminal)
- URL
- Text
This resolves#4932
#4235 introduced a crash when you closed the last tab in a window. In
`NotebookAdw.closeTab` a `defer` was added that references `self`. If
the last tab is closed we destroy the window. As part of that process
`self` becomes invalid because the window has been de-initialized. The
`defer` fires at the end of the function, referencing the invalid
pointer and causing a crash.
```
info(surface): surface closed addr=7fffe400a000
debug(gtk): window destroy
(process:1032400): Gtk-CRITICAL **: 18:40:17.674: gtk_widget_unparent: assertion 'GTK_IS_WIDGET (widget)' failed
Segmentation fault at address 0x7ffff4dad040
/home/jeff/dev/ghostty/src/apprt/gtk/notebook_adw.zig:128:19: 0x340226a in closeTab (ghostty)
defer self.forcing_close = false;
^
/home/jeff/dev/ghostty/src/apprt/gtk/notebook.zig:157:40: 0x336ca86 in closeTab (ghostty)
.adw => |*adw| adw.closeTab(tab),
^
/home/jeff/dev/ghostty/src/apprt/gtk/Window.zig:468:27: 0x327628d in closeTab (ghostty)
self.notebook.closeTab(tab);
^
/home/jeff/dev/ghostty/src/apprt/gtk/Tab.zig:121:25: 0x336581b in remove (ghostty)
self.window.closeTab(self);
^
/home/jeff/dev/ghostty/src/apprt/gtk/Surface.zig:207:34: 0x326a213 in remove (ghostty)
.tab_ => |t| t.remove(),
^
/home/jeff/dev/ghostty/src/apprt/gtk/Surface.zig:722:30: 0x31e3a3a in close (ghostty)
self.container.remove();
^
/home/jeff/dev/ghostty/src/Surface.zig:733:26: 0x31e1dc4 in close (ghostty)
self.rt_surface.close(self.needsConfirmQuit());
^
/home/jeff/dev/ghostty/src/Surface.zig:925:23: 0x31e143e in handleMessage (ghostty)
self.close();
^
/home/jeff/dev/ghostty/src/App.zig:486:34: 0x31e2d05 in surfaceMessage (ghostty)
try surface.handleMessage(msg);
^
/home/jeff/dev/ghostty/src/App.zig:252:62: 0x31e3005 in drainMailbox (ghostty)
.surface_message => |msg| try self.surfaceMessage(msg.surface, msg.message),
^
/home/jeff/dev/ghostty/src/App.zig:138:26: 0x31e378e in tick (ghostty)
try self.drainMailbox(rt_app);
^
/home/jeff/dev/ghostty/src/apprt/gtk/App.zig:1279:31: 0x31e3e42 in run (ghostty)
try self.core_app.tick(self);
^
/home/jeff/dev/ghostty/src/main_ghostty.zig:112:24: 0x31e52f4 in main (ghostty)
try app_runtime.run();
^
/nix/store/h6lccra69nr23676qq32h9qn1fba24v1-zig-0.13.0/lib/std/start.zig:524:37: 0x31e5e0e in main (ghostty)
const result = root.main() catch |err| {
^
???:?:?: 0x7ffff682a1fb in ??? (libc.so.6)
Unwind information for `libc.so.6:0x7ffff682a1fb` was not available, trace may be incomplete
fish: Job 2, './zig-out/bin/ghostty --config-…' terminated by signal SIGABRT (Abort)
```
As of version 1.0.1 (macOS build) when running the toggle visibility
action a window with tabs is made into multiple windows.
This PR ensures terminal tabs are reconstructed and correctly placed
into its parent window.
# Demo
https://github.com/user-attachments/assets/44f14bca-15a1-4717-ba0a-44f0767feec3
FYI: I will create another PR to ensure the right tab is focused after
the main window is restored.
Solves #4329
Two major changes:
1. Hiding uses `NSApp.hide` which hides all windows, preserves tabs, and
yields focus to the next app.
2. Unhiding manually tracks and brings forward only the windows we hid.
Proper focus should be retained.
Fixes#4799
This PR attempts to reduce the flash caused by the ghost emoji in the
title bar when opening new windows.
## Changes:
- Initialize `SurfaceView.title` with empty string instead of ghost
emoji
- Simplify title computation logic in `TerminalView`
- Adding a 500ms fallback timer for "👻"
- Canceling timer if title is set
## Current Status:
While these changes reduce the initial ghost emoji flash, there's still
a brief moment where a folder emoji appears alone in the title bar when
opening a new window. This suggests there might be a race condition or
timing issue with how the title is being set and updated.
https://github.com/user-attachments/assets/3688c9f3-1727-4379-b04d-0bd6ac105728
Would appreciate feedback on the remaining flash issue and suggestions
for further improvements.
There's one behavioral change here. Before this patch, if
`gtk-titlebar=false` we _never_ created a headerbar. This explicitly
contradicted the comments in the source, and the documentation for
`gtk-titlebar` imply that if a window starts out without a titlebar it
can be brought back later with the `toggle_window_decorations` keybind
action.
After this patch, a headerbar is always created, but if
`gtk-titlebar=false` or `window-decoration=false` it's immediately
hidden.
I'm not sure how this interacts with the current SSD/CSD detection that
seems to happen when running Ghostty on non-Gnome DEs so it'll be
important to get #4724 merged (plus any follow ups) to enable more
explicit control of SSD/CSD.
This is a hack to make it easier for our GitHub branching rules to
require a single check to pass before merging. This lets us describe the
required checks in code rather than via the GH UI.
This is a hack to make it easier for our GitHub branching rules to
require a single check to pass before merging. This lets us describe the
required checks in code rather than via the GH UI.
This PR addresses https://github.com/ghostty-org/ghostty/issues/4732.
While @tristan957 suggested alternative approaches, this implementation
provides a straightforward way to make the menu accessible when the
window decoration is disabled. It follows patterns seen in other GTK
apps for handling submenus, though not strictly in the context menu
format truth be told.
If there’s a better way to approach this or further refinements needed,
I’m happy to discuss and iterate. This has been a minor issue I’ve
encountered personally, and I’d like to help improve the experience for
others as well.
Small video of how it looks:
https://github.com/user-attachments/assets/59548fef-f11c-421f-b05b-be81eab6ce06
Fixes:
https://github.com/ghostty-org/ghostty/issues/4634#issuecomment-2573469532
This commit fixes two issues:
1. `libghostty` must not override ctrl+key inputs if we are in a preedit
state. This allows thigs like `ctrl+h` to work properly in an IME.
2. On macOS, when an IME commits text, we strip the control modifier
from the key event we send to libghostty. This is a bit of a hack but
this avoids triggering special ctrl+key handling.
Fixes: https://github.com/ghostty-org/ghostty/issues/4634#issuecomment-2573469532
This commit fixes two issues:
1. `libghostty` must not override ctrl+key inputs if we are in a preedit
state. This allows thigs like `ctrl+h` to work properly in an IME.
2. On macOS, when an IME commits text, we strip the control modifier
from the key event we send to libghostty. This is a bit of a hack but
this avoids triggering special ctrl+key handling.
Fixes#4801
Our size calculation before improperly used a screens frame instead of
its visibleFrame. Additionally, we didn't properly account for origin
needing to move in order to fit the window on the screen.
Apparently, setting a frame height to high crashes AppKit. The width
gets clamped by AppKit but the height does not. Fun!
Fixes#4801
Our size calculation before improperly used a screens frame instead of
its visibleFrame. Additionally, we didn't properly account for origin
needing to move in order to fit the window on the screen.
Apparently, setting a frame height to high crashes AppKit. The width
gets clamped by AppKit but the height does not. Fun!
A "size-limit" function has been implemented for GTK which calls
gtk_widget_set_size_request() to set the minimum widget/window size.
Without
this function, it's left to GTK to set the minimum size which is usually
a lot larger than the documented 10x4 cell minimum size. This doesn't
fix the
issue completely as GTK retains the final say in how small a window can
be
but it gets closer.
Resolves: #4836
A "size-limit" function has been implemented for GTK which calls
gtk_widget_set_size_request() to set the minimum widget/window size. Without
this function, it's left to GTK to set the minimum size which is usually
a lot larger than the documented 10x4 cell minimum size. This doesn't fix the
issue completely as GTK retains the final say in how small a window can be
but it gets closer.
Resolves: #4836
## Description
This PR implements the `copy_url_to_clipboard` keybind action. This
action allows users to copy URLs directly to the clipboard without
needing to select them first.
### Features
- Works with both regex-matched URLs and OSC8 hyperlinks
- Copies only the URL portion, not the surrounding text
- Respects the `clipboard_trim_trailing_spaces` configuration
- Provides clear error feedback
- Follows the same patterns as other clipboard operations
https://github.com/user-attachments/assets/c9c82e3d-dfc5-4171-b367-d6799305d87f
Resolves https://github.com/ghostty-org/ghostty/issues/4633
This produces the following keybind, which I believe was intended.
> keybind = cmd+backspace=text:\x15
Matches the cmd+left and cmd+right which are a few lines up.
#3679#3646
This allows dropping files and strings onto Ghostty in the GTK apprt. If
you drop files onto Ghostty it will be pasted as a list of shell-escaped
paths separated by newlines. If you drop a string onto Ghostty it will
paste the string. Normal rules for pasting (bracketed pasts, unsafe
pastes) apply.
read(2) returning 0 means that the other end of the pipe/pty has been
closed (EOF), so there cannot be any more output to read on the pipe,
and
the io reader thread can just exit.
If exec.wait_after_command=false, the read thread's quit pipe is
immediately written to after the child process dies, so all is well.
However, if wait_after_command=true (which is the case when using
Ghostty
to run a .command/.sh file on macOS), the read thread keeps spinning,
causing persistent 100% CPU usage per exited process.
Fix it by exiting the reader thread on EOF.
If the read thread has already exited, it will have closed the read end
of the quit pipe. Unless SIGPIPE is masked with signal(SIGPIPE, SIG_IGN),
or the macOS-specific fcntl(F_SETNOSIGPIPE), writing to the write end of
a broken pipe kills the writer with SIGPIPE instead of returning -EPIPE
as an error. This causes a crash if the read thread exits before
threadExit.
This was already a possible race condition if read() returns
error.NotOpenForReading or error.InputOutput, but it's now much easier to
trigger due to the recent "termio/exec: fix 100% CPU usage after
wait-after-command process exits" fix.
Fix this by closing the quit pipe instead of writing to it.
This PR adds support for a dedicated `close_tab` keybinding action,
allowing users to bind specific keys for closing tabs. The
implementation:
- Adds `close_tab` as a new keybinding action
- Preserves all existing confirmation dialogs for running processes
- Works seamlessly with macOS native tab system
### Testing
- [x] Tested with single tabs
- [x] Tested with multiple tabs
- [x] Tested with running processes (confirmation dialog)
- [x] Tested with splits within tabs
<img width="797" alt="image"
src="https://github.com/user-attachments/assets/8e09eea3-1f71-40a3-a835-76de14013a29"
/>
https://github.com/user-attachments/assets/155210f7-20fe-4a96-8800-6969df214871
Partially resolved#4331
closes#2721
This PR resolves the issue where the Quick Terminal was not visible when
pressing the global keybind while a full-screen app was active.
### Changes
- Added new configuration options for `quick-terminal-space-behavior`
- The Quick Terminal will now overlay properly on top of full-screen
applications
#### Behavior
##### `quick-terminal-space-behavior = remain`
- The Quick Terminal will be remain open on the space when switching
spaces.
##### `quick-terminal-space-behavior = move`
- The Quick Terminal will be moved to active space when switching
spaces.
If the title is already the current working directory, hide the
subtitle. Otherwise show the current working directory, like if a
command is running for instance.
This is a re-opening of my original PR because I had to delete my fork
and re-fork it.
The reasoning for this PR is discussed at
https://github.com/ghostty-org/ghostty/discussions/3667
But in short, `pkg-config` queries `libadwaita-1` successfully, but not
for `adwaita-1`, hence renaming it would result in better integration
with pkg-config.
As discussed in #2670 and #2722
- This uses an NSPasteboard with the name
`com.mitchellh.ghostty.selection` as a dedicated 'selection' clipboard
- Sets `supports_selection_clipboard` to true for macOS
- Sets the default `copy-on-select` config to `.true` for macOS
- Adds a "Paste Selection" menu item and default cmd+shift+v key binding
for macOS (to match Terminal.app)
Adds the missing Bluetooth permission to Ghostty's application playlist
manifest file, as it was missing. Tweaks have also been made to existing
permission descriptions to be more readable. Should fix an abrupt crash
in Fastfetch and any other apps that may request Bluetooth permissions.
### apprt/gtk: Add version.runtimeAtLeast
This will be used for version checks that are independent of the version
of GTK we built against.
### apprt/gtk: Move most version checks to runtime
Unless we are guarding against symbols added in new versions we now
check against the runtime version of GTK to handle them even when we
didn't build against that version.
This is a major refactor of `build.zig` aimed at improving
maintainability while also fixing some bugs.
The major idea behind the refactor is to split the `build.zig` file up
into distinct `src/build/*.zig` files. By doing so, we can improve
readability of the primary `build.zig` while also enabling better reuse
of steps. Our `build.zig` is now less than 150 lines of code (of course,
it calls into a lot more lines but they're neatly organized now).
Ignore the commit messages I'm going to squash this whole thing.
Improvements:
* `build.zig` is less than 150 lines of readable code.
* Help strings and unicode table generators are only run once when
multiple artifacts are built since the results are the same regardless
of target.
* Metal lib is only built once per architecture (rather than once per
artifact)
* Resources (shell integration, terminfo, etc.) and docs are only
built/installed for artifacts that need them
* Wayland protocols no longer required for source build
Breaking changes:
* Removed broken wasm build (@gabydd will re-add)
* Removed conformance files, shell scripts are better and we don't run
these anymore
* Removed macOS app bundle creation, we don't use this anymore since we
use Xcode
## Extra: Some History
Our `build.zig` hasn't been significantly refactored since the project
started, when Zig was _version 0.10_. Since then, the build system has
changed significantly. We've only ever duct taped the `build.zig` as we
needed to support new Zig versions, new features, etc. It was a mess.
The major improvement is adapting the entire Ghostty `build.zig` to the
Step and LazyPath changes introduced way back in Zig 0.12. This lets us
better take advantage of parallelism and the dependency graph so that
steps are only executed as they're needed.
As such, you can see in the build.zig that we initialize a lot of
things, but unless a final target (i.e. install, run) references those
steps, _they'll never be executed_. This lets us clean up a lot.
'--posix' starts bash in POSIX mode (like /bin/sh). This is rarely used
for interactive shells, and removing automatic shell integration support
for this option allows us to simply/remove some exceptional code paths.
Users are still able to manually source the shell integration script.
Also fix an issue where we would still inject GHOSTTY_BASH_RCFILE if we
aborted the automatic shell integration path _after_ seeing an --rcfile
or --init-file argument.
This refactor enables two very significant improvements to our font
handling, which I will be implementing next:
1. Automatically adjust size of fallback faces to better align with the
primary face, a la CSS
[`font-size-adjust`](https://developer.mozilla.org/en-US/docs/Web/CSS/font-size-adjust).
[^1]
2. Move glyph resizing/positioning out of GPU-land and in to
`renderGlyph` and apply alignment/resizing rules from the nerd fonts
patcher[^2] to the glyphs at rasterization time, so that we can ensure
exact cell fits and swap out our embedded JB Mono with an unpatched
version with a separate dedicated symbols-only nerd font.
In addition to being necessary prep work for those two changes, this PR
is also a minor but real stand-alone improvement. By only computing the
cell metrics for our primary font, we avoid a *lot* of wasted work when
loading fallback fonts, and also avoid that being a source of load
errors, which we don't yet handle gracefully[^3].
To validate this PR I've run the full set of font backend tests locally
on my Mac with no failures, and did a sanity check of running Ghostty
with both renderers and with CoreText and FreeType font backends and
then `cat`ing a file that requires fallback fonts to render, and
everything looks correct.
[^1]: #3029
[^2]: The alignment and resizing rules for the nerd font symbols are
defined in the patcher
[here](6d0b8ba05a/font-patcher (L866-L1151))
[^3]: #2991
PS0 is evaluated after a command is read but before it is executed. The
'preexec' hook (from bash-preexec) is equivalent for our title-updating
purposes and conveniently provides the current command as an argument
(from its own `history 1` call).
The major idea behind the refactor is to split the `build.zig` file up into
distinct `src/build/*.zig` files. By doing so, we can improve readability of
the primary `build.zig` while also enabling better reuse of steps. Our
`build.zig` is now less than 150 lines of code (of course, it calls into a lot
more lines but they're neatly organized now).
Improvements:
* `build.zig` is less than 150 lines of readable code.
* Help strings and unicode table generators are only run once when multiple
artifacts are built since the results are the same regardless of target.
* Metal lib is only built once per architecture (rather than once per artifact)
* Resources (shell integration, terminfo, etc.) and docs are only
built/installed for artifacts that need them
Breaking changes:
* Removed broken wasm build (@gabydd will re-add)
* Removed conformance files, shell scripts are better and we don't run
these anymore
* Removed macOS app bundle creation, we don't use this anymore since we
use Xcode
## Some History
Our `build.zig` hasn't been significantly refactored since the project started,
when Zig was _version 0.10_. Since then, the build system has changed
significantly. We've only ever duct taped the `build.zig` as we needed to
support new Zig versions, new features, etc. It was a mess.
The major improvement is adapting the entire Ghostty `build.zig` to the Step
and LazyPath changes introduced way back in Zig 0.12. This lets us better take
advantage of parallelism and the dependency graph so that steps are only
executed as they're needed.
As such, you can see in the build.zig that we initialize a lot of things, but
unless a final target (i.e. install, run) references those steps, _they'll
never be executed_. This lets us clean up a lot.
'--posix' starts bash in POSIX mode (like /bin/sh). This is rarely used
for interactive shells, and removing automatic shell integration support
for this option allows us to simply/remove some exceptional code paths.
Users are still able to manually source the shell integration script.
Also fix an issue where we would still inject GHOSTTY_BASH_RCFILE if we
aborted the automatic shell integration path _after_ seeing an --rcfile
or --init-file argument.
Unless we are guarding against symbols added in new versions we now
check against the runtime version of GTK to handle them even when we
didn't build against that version.
## Description
This PR adds support for IPv6 URL detection in terminal output,
addressing issue #4743. The implementation enhances URL detection to
properly handle IPv6 addresses in URLs, including various formats and
use cases.
## Changes
- Added dedicated IPv6 URL pattern matching
- Integrated IPv6 pattern with existing URL regex
- Added comprehensive test suite for IPv6 URL scenarios
## Test Cases
The implementation includes test cases for:
- Basic IPv6 URLs (e.g., `http://[::]:8000/`)
- Full IPv6 addresses with ports
- Compressed IPv6 forms
- URLs with paths and query parameters
- Special cases (link-local, multicast)
- Context-specific scenarios (markdown)
## Related Issues
Resolves#4743
PS0 is evaluated after a command is read but before it is executed. The
'preexec' hook (from bash-preexec) is equivalent for our title-updating
purposes and conveniently provides the current command as an argument
(from its own `history 1` call).
- Add IPv6 URL pattern matching to support URLs like http://[::]:8000/
- Separate IPv6 URL pattern from main regex for better maintainability
- Add extensive test cases covering:
- Basic IPv6 URLs with ports
- URLs with paths and query parameters
- Compressed IPv6 forms
- Link-local and multicast addresses
- Mixed scenarios and markdown contexts
This sets the stage for dynamically adjusting the sizes of fallback
fonts based on the primary font's face metrics. It also removes a lot of
unnecessary work when loading fallback fonts, since we only actually use
the metrics based on the parimary font.
**Overview**: add support for file paths starts with `../` `./` and `/`
To implement this I extended the existing regex variable in the
`src/config` dir. In a few test cases, extra space is added
intentionally to verify we don't include space in the URL as it looks &
feels odd.
Here is the text file content used for testing
```console
➜ ~ cat test.txt
https://google.com
file:///Users/ABC/oss/ghostty/build.zig
file:///Users/ABC/oss/ghostty/debug.sh
/Users/ABC/oss/ghostty/src/../debug.sh
../../Applications/Zed.app/Contents/Info.plist
[link](/home/user/ghostty.user/example) -- non-existent
[link](/Users/ABC/oss/ghostty/src/../debug.sh)
first time ../../Applications/Zed.app/Contents/Info.plist contributor
➜ ~
```
Here is the screen recording of the changes.
[](https://www.youtube.com/watch?v=Q8qdwdBVbWk)
Related to #4485
This commit matches ConEmu's parsing logic[^1] more faithfully. For any
substate that requires a progress, ConEmu parses so long as there is a
number and then just ignores the rest.
For substates that don't require a progress, ConEmu literally ignores
everything after the state.
Tests cover both.
[^1]:
740b09c363/src/ConEmuCD/ConAnsiImpl.cpp (L2264)
Remove all window corner artifacting. Now we also respond to changes
when the window becomes decorated or not.
Signed-off-by: Tristan Partin <tristan@partin.io>
Related to #4485
This commit matches ConEmu's parsing logic[^1] more faithfully. For any
substate that requires a progress, ConEmu parses so long as there is a
number and then just ignores the rest.
For substates that don't require a progress, ConEmu literally ignores
everything after the state.
Tests cover both.
[^1]: 740b09c363/src/ConEmuCD/ConAnsiImpl.cpp (L2264)
To implement this I extended the existing regex variable in the `src/config` dir. In a few test cases, extra space is added intentionally to verify we don't include space in the URL as it looks & feels odd.
Fixes#4703
This changes `unbind` so it always removes all keybinds with the given
trigger pattern regardless of if it is translated or physical.
The previous behavior was technically correct, but this implements the
pattern of least surprise. I can't think of a scenario where you really
want to be exact about what key you're unbinding. And if that scenario
does exist, you can always fix it by rebinding after unbind.
Fixes#4703
This changes `unbind` so it always removes all keybinds with the given
trigger pattern regardless of if it is translated or physical.
The previous behavior was technically correct, but this implements the pattern
of least surprise. I can't think of a scenario where you really want to
be exact about what key you're unbinding. And if that scenario does
exist, you can always fix it by rebinding after unbind.
A simple change to make it so that, in the GTK4 paste confirmation
dialog, the user can just hit enter/space to confirm the paste.
After some playing around, it seems as though GTK4 needs you to set the
focus on a widget after the entire view has been configured, meaning
that we have to create more references to pass the `confirm_button`
GtkWidget up and up. Not 100% certain if this is the best way to do so,
but:
1. Add the `ButtonsView` to the `PrimaryView` struct (as
`PrimaryView.buttons`)
2. Add the `confirm_button` to the `ButtonsView` struct (as
`ButtonsView.confirm_button`)
3. Call `c.gtk_widget_grab_focus` on (the now-accessible)
`view.buttons.confirm_button`
This seems to work as expected, but I'm not sure if:
1. We should also make `cancel_button` available?
2. There's a better way to expose `confirm_button` to `PrimaryView`?
3. I did a good Zig?
I've never written (or read) Zig code before today so I hope this makes
sense. Feedback welcome!
Adds the missing Bluetooth permission description to ghostty's Xcode
project description, and fixes up existing permissions to be clearer.
Closes#3995 and #4512.
If the title is already the current working directory, hide the
subtitle. Otherwise show the current working directory, like if
a command is running for instance.
Signed-off-by: Tristan Partin <tristan@partin.io>
Basically integrates `ghostty +validate-config` with vim's compiler
feature. This allows validating the config from vim and navigating to
errors e.g. with the quickfix list.
Fixes#4509
Our config has a replay system so that we can make changes and reproduce
the configuration as if we were reloading all the files. This is useful
because it lets us "reload" the config under various conditions (system
theme change, etc.) without risking failures due to world state changing
(i.e. config files change or disappear).
The replay system assumed that all diagnostics were reproducible, but
this is not the case. For example, we don't reload `config-file` so we
can't reproduce diagnostics that come from it.
This commit adds a new `diagnostic` replay step that can be used to
store non-reproducible diagnostics and `config-file` is updated to use
it.
Fixes#4509
Our config has a replay system so that we can make changes and reproduce
the configuration as if we were reloading all the files. This is useful
because it lets us "reload" the config under various conditions (system
theme change, etc.) without risking failures due to world state changing
(i.e. config files change or disappear).
The replay system assumed that all diagnostics were reproducible, but
this is not the case. For example, we don't reload `config-file` so we
can't reproduce diagnostics that come from it.
This commit adds a new `diagnostic` replay step that can be used to
store non-reproducible diagnostics and `config-file` is updated to use
it.
Also establishes a foundation for Wayland support and fixes a minor bug
(GTK windows remaining opaque when `background-opacity` is set to 1 on
startup and later updated to less than 1 with a config reload)
Can't update the Zig cache hash myself since I'm currently in China and
my proxy's broken for some reason :(
See also #4361, part of #4626
This is achieved by rendering to an alpha-only context rather than a
normal single-channel context, and adjusting the brightness at which
CoreText thinks it's drawing the glyph, which affects how it applies
font smoothing (which is what `font-thicken` enables).
Currently the `background` CSS class is added once on startup and never removed
or re-added. This is problematic as that if Ghostty was started with an opaque
window but then its config was reloaded with a `background-opacity` less than 1,
the window won't actually become translucent, and it would only appear as if the
background colors had become faded (because the window is still styled to be
opaque).
`:make` will call `ghostty +validate-config` and populate the quickfix
list with the errors that can be navigated to (e.g. with `:cnext`)
`:h write-compiler-plugin`, and neovim's built in ftplugin/ and
compiler/ plugins were used as references
- **gtk: send copy_to_clipboard toast from Surface**
Move the toast we send when copying to the clipboard to the Surface
implementation. Previously, we only called this from the gtk accelerator
callback which we only call when the *last set* keybind is activated.
We also only send a toast if we have copied to the standard clipboard,
as opposed to the selection clipboard. By default, we have
copy-to-clipboard true for linux, which sets the selection keyboard on
any select. This becomes *very* noisy.
- **config: rearrange default copy_to_clipboard keybinds**
Move the newly added *+insert keybinds to before the ctrl+shift+*
keybinds. This is needed to have the ctrl+shift keybinds be the ones
that show up in the menu.
Move the newly added *+insert keybinds to before the ctrl+shift+*
keybinds. This is needed to have the ctrl+shift keybinds be the ones
that show up in the menu.
Move the toast we send when copying to the clipboard to the Surface
implementation. Previously, we only called this from the gtk accelerator
callback which we only call when the *last set* keybind is activated.
We also only send a toast if we have copied to the standard clipboard,
as opposed to the selection clipboard. By default, we have
copy-to-clipboard true for linux, which sets the selection keyboard on
any select. This becomes *very* noisy.
Fixes#4539
AquaSKK is a Japanese IME (Input Method Editor) for macOS. It uses
keyboard inputs to switch between input modes. I don't know any other
IMEs that do this, but it's possible that there are others. Prior to
this change, the keyboard inputs to switch between input modes were
being sent to the terminal, resulting in erroneous characters being
written.
This change adds a check during keyDown events to see if the input
source changed _during the event_. If it did, we assume an IME captured
it and we don't pass the event to the terminal.
This makes AquaSKK functional in Ghostty.
Fixes#4539
AquaSKK is a Japanese IME (Input Method Editor) for macOS. It uses
keyboard inputs to switch between input modes. I don't know any other
IMEs that do this, but it's possible that there are others. Prior to
this change, the keyboard inputs to switch between input modes were
being sent to the terminal, resulting in erroneous characters being
written.
This change adds a check during keyDown events to see if the input
source changed _during the event_. If it did, we assume an IME captured
it and we don't pass the event to the terminal.
This makes AquaSKK functional in Ghostty.
yet another follow up to #4534
some notes:
- different parts of the build system link against freetype2 or freetype
with freetype2 being the name for the pkg-config file. Because of the
include path in freetype-zig.h the pkg-config is needed otherwise it
would be unable to find the headers. The change isn't technically needed
for the harfbuzz and fontconfig modules however I think its best to keep
them all consistent since otherwise it might cause build errors in non
standard setups
- looking back, I initially modelled buildLib after the build function
and kept the pub, none of them need to be public so I've gone ahead and
removed all of that
test logic was kept just as they were before with a setup exact like it
was done for oniguruma
the main program and the testsall seem to work just fine both with and
without system integration
Sorry for the vague title. This PR addresses multiple issues:
1. Fixes#4540
2. #4522 is fixed for macOS only
3. Fixes#4590
4. Fixes an untracked issue where `command+key` events will not send
release events for Kitty keyboard protocol, something I only noticed
while working on this.
There are multiple components to this PR.
## Part 1: `App/Surface.keyEventIsBinding`
This new API (also available in libghostty as
`ghostty_surface_key_is_binding`) returns a boolean true if the given
key event would match a binding trigger if it was the next key event
sent. It does not process the binding now.
This can be used by event handlers that intercept key events to
determine if it should send the event to Ghostty. This helps resolve
#4590 for us but is also part of all resolved issues.
## Part 2: macOS `performKeyEquivalent` changes
macOS calls `performKeyEquivalent` for any key combination that may
trigger a key equivalent. if this returns `true` then it is handled and
macOS ceases processing the event.
We were already using this to intercept things like `Ctrl+/` which
triggers a context menu in macOS Sequoia. But we now expand this to
intercept all events to check for bindings. This lets us fix#4590.
Additionally, it's been changed to special case `cmd+period`. I'm sure
more need to be added.
## Part 3: NSEvent local listener for command keyUp events
macOS simply doesn't send `keyUp` events for key events with command
pressed. The only way to work around this is to register an `NSEvent`
local listener. We now do this. This fixes the untracked issue noted
above.
As a new user of ghostty, it was not intuitive to figure out how to
provide the `offset` parameter. It makes sense when you look more of the
rest of the options but I think we can still make these docs cleaner,
like I have done in this PR.
Thanks!
This changes quit signaling from a boolean return from core app `tick()`
to an apprt action. This simplifies the API and conceptually makes more
sense to me now.
This wasn't done just for that; this change was also needed so that
macOS can quit cleanly while fixing #4540 since we may no longer trigger
menu items. I wanted to split this out into a separate commit/PR because
it adds complexity making the diff harder to read.
This changes quit signaling from a boolean return from core app `tick()`
to an apprt action. This simplifies the API and conceptually makes more
sense to me now.
This wasn't done just for that; this change was also needed so that
macOS can quit cleanly while fixing #4540 since we may no longer trigger
menu items. I wanted to split this out into a separate commit/PR because
it adds complexity making the diff harder to read.
This changes quit signaling from a boolean return from core app `tick()`
to an apprt action. This simplifies the API and conceptually makes more
sense to me now.
This wasn't done just for that; this change was also needed so that
macOS can quit cleanly while fixing #4540 since we may no longer trigger
menu items. I wanted to split this out into a separate commit/PR because
it adds complexity making the diff harder to read.
running `zig build --help` was crashing for some people, I narrowed it
down to gtk4 not being installed however that shouldn't make the help
message not nor should it block glfw builds
In #4388, documentation was added for goto_split but in #3427 this
documentation was made outdated but not updated. This makes the
documentation up to date and brings the ordering in line with new_split
follow-up to #4520
all the same stuff for the previous two
the tests for this only run for the native target and was added for the
iOS build (3360a008cd), I've made a second
version of this commit to remove the native check if thats more desired
(d247a22de036140297942701090e0eafb3d1a72d)
ghostty and all tests appear to run on my system both with and without
system integration
In #4388, documentation was added for goto_split but in #3427 this
documentation was made outdated but not updated. This makes the
documentation up to date and brings the ordering in line with new_split
This is achieved by rendering to an alpha-only context rather than a
normal single-channel context, and adjusting the brightness at which
coretext thinks it's drawing the glyph, which affects how it applies
font smoothing (which is what `font-thicken` enables).
Fixes#4518
If our UTF8 encoding is not recognized, we fall back to the ASCII
mapping of the logical key for the control sequence. This allows
cyrillic control characters to work.
I also verified that non-cyrllic (US) and alternate layouts (Dvorak)
work as expected still.
same as #4205 but for fontconfig
it follows the same pattern with one addition:
the module needs a known target to be able to link a system library
I don't think this will affect anything
ghostty and all tests appear to run on my system both with and without
system integration
Fixes#4518
If our UTF8 encoding is not recognized, we fall back to the ASCII
mapping of the logical key for the control sequence. This allows
cyrillic control characters to work.
I also verified that non-cyrllic (US) and alternate layouts (Dvorak)
work as expected still.
The cimgui version listed does not match the upstream commit or the
vendored cimgui files
Checking the upstream `git log` the commit corresponds to `commit
e391fe2e66eb1c96b1624ae8444dc64c23146ef4 (tag: v1.90.6-docking)` however
the `build.zig.zon` is outdated.
The vendored cimgui files also contain the header
```cpp
// This file is automatically generated by generator.lua from
// https://github.com/cimgui/cimgui based on imgui.h file version "1.90.6" 19060
// from Dear ImGui https://github.com/ocornut/imgui with imgui_internal.h api
// docking branch
```
I wasn't too clear with what the comment meant:
```
// This should be kept in sync with the submodule in the cimgui source
// code to be safe that they're compatible.
```
and assumed it was referring to the vendored cimgui files, added a
comment pointing out where to find the cimgui source mentioned.
When searching in the theme list (e.g., searching for "Snazzy"), some matching themes might be hidden due to incorrect window position handling.
This fix ensures all matching themes are visible by adjusting the window position logic.
Current sort used by `+list-keybinds` doesn't include the value of the
key:
```
ctrl + shift + v paste_from_clipboard
ctrl + shift + a select_all
...
ctrl + shift + q quit
ctrl + shift + n new_window
...
alt + five goto_tab:5
alt + eight goto_tab:8
...
alt + six goto_tab:6
alt + seven goto_tab:7
```
adding the key value improves the sort order
```
ctrl + shift + a select_all
ctrl + shift + c copy_to_clipboard
...
ctrl + shift + n new_window
ctrl + shift + o new_split:right
ctrl + shift + q quit
...
alt + one goto_tab:1
alt + two goto_tab:2
alt + three goto_tab:3
...
alt + eight goto_tab:8
alt + nine last_tab
alt + f4 close_window
closes#4328closes#3970
makes this possible now
```
keybind = performable:ctrl+c=copy_to_clipboard # copy if theres a selection else send sigint
keybind = ctrl+v=paste_from_clipboard
```
After updating to 1.0.1 I noticed something different in the terminal,
which turned out being the window borders - it appeared as if Ghostty
was using light-mode style borders (dark/black outline with a thin light
stroke at the top) instead of the entire light outline from before:
| 1.0.0 | 1.0.1 |
| - | - |
| <img width="308" alt="Screenshot 2025-01-01 at 2 28 12 PM"
src="https://github.com/user-attachments/assets/d8bc5bdd-c3b2-401c-a8ed-9da0b768cb3d"
/> | <img width="308" alt="Screenshot 2025-01-01 at 2 29 07 PM"
src="https://github.com/user-attachments/assets/fd710bed-1756-4f66-8402-bfbdd25218ab"
/> |
After digging a bit, I found #3834, which fixes fullscreen background
colors through alpha channels by appending a `withAlphaComponent(0.0)`
to `backgroundColor` - for reasons I may be entirely unaware of (since
I'm not a Swift developer), this seems to cause the dark-mode border
style to go away.
Some lines above that, I noticed the `.clear` callout from line 266,
which talks about matching Terminal.app's styles, and it _also_ has a
`withAlphaComponent` but set to `0.001` - if I understand correctly, and
the fix from #3834 works by setting the alpha component to a
_practically_ zero value, then I thought perhaps a really small number
like `0.001` could do the trick as well. This ended up working and
bringing back the right borders again.
Not sure again if this may make a difference anywhere else in the app or
bring any undesired behavior, but if anyone who is well-versed in Swift
would like chime in with more details or perhaps a better approach, I'd
greatly appreciate it!
Closes https://github.com/ghostty-org/ghostty/issues/4089
Gave it a shot and implemented the custom css loading.
My general idea is to use a provider for each stylesheet the user wants
to load and then when the config changes unload them and create new
providers.
A separate provider has to be used for each stylesheet the user wants to
load, since when the provider loads the css it clears all the previously
loaded styles, so in effect we cannot use one provider to load multiple
stylesheets, but maybe there is a better way to overcome this limitation
which I'm not seeing.
makes use of the system harfbuzz if system integration is enabled
otherwise it builds the library and uses it in the module
this has the added benefit that package maintainers don't have to ship a
separate copy of harfbuzz and worry about compatibility with the system
library
Some notes:
- the logic to build the library has been split into a separate function
- needed options are passed as an anonymous struct because its so
minimal that there really is not need for an explicit type
- unlike `Build.systemIntegrationOption`, `Build.option` cannot be
called mutiple times to declare it before its used
tests appear to run on my system both with and without system
integration
The documentation used to say e.g. "The format of the color is the same
as the `background` configuration; see that for more information.", yet
`background` left the format actually undocumented.
To avoid people having to jump around the docs to find out the supported
formats, the prose for the formats is repeated for each color.
I dug around a bit to find out that named colors from the default X11
map are also a supported format (`cursor-color = purple` works fine), so
that's now documented too.
https://github.com/ghostty-org/ghostty/discussions/4107#discussioncomment-11699228
I was confused about not being able to run `ghostty +new_window` since I
hadn't read the docs closely enough to understand the distinction
between Keybind Actions and CLI Actions.
I think if the error messages I've modified here would have read this
way to begin with I would've had a better chance of discovering this
distinction on my own.
I did read the Contributing guidelines but I avoided opening an Issue
since the changes here are minimal enough that I felt it would just add
noise. If that's a mistake then I'm happy to close this out and return
to the original discussion and/or create a new Issue.
\+ much more flexible syntax and lenient parser
\+ allows comma-separated list as a single config value
This allows, e.g. `cv01 = 2` to select the second variant of `cv01`.
Resolves#3128
Parser could probably be a little smaller than it is- would be a lot
cleaner with the labeled switch continue pattern from Zig 0.14. Maybe
should've put it in its own file too...
I spent *much* too long trying to test this with `cv01` with
[monaspace](https://github.com/githubnext/monaspace) before realizing
that the README refers to v1.2 but the latest released version (and
hence the one I had installed) was v1.101 -- I installed the v1.2
version and tested with both CoreText and HarfBuzz and successfully set
`cv01 = 2` and got the expected result.
Feel free to make any stylistic changes you feel necessary before
merging.
Fixes#3229
Gets the desired behavior for #3229, I'm unsure if there is a nicer way
to omit the mouse motion events from the event controller
when the glarea is resized due to the splitting behavior. Thresholding
to 1px is required because just checking for equality results
in the focus still being stolen sometimes. This is kinda of a hack so a
nicer solution would be much appreciated!
This disables compiling/linking Sentry automatically on platforms other
than macOS, which removes a potential blocker for getting Ghostty
running on *BSD or other systems.
This is also useful for the security paranoid that don't want any chance
that sensitive information could be captured in a crash dump.
adds the option "strip" which can be used to override the default strip
setting, which is based on the optimization mode.
Useful for a distro setting where you want a release build but still
keep symbols.
Also reuses the option for the shared and static library
When unset, we use Sparkle's default behavior, which is based on the
user's preference stored in the standard user defaults.
The rest of the previous behavior is preserved:
- When SUEnableAutomaticChecks is explicitly false, auto-updates are
disabled.
- When 'auto-update' is set, use its value to set Sparkle's auto-update
behavior.
Fixes#4433
When unset, we use Sparkle's default behavior, which is based on the
user's preference stored in the standard user defaults.
The rest of the previous behavior is preserved:
- When SUEnableAutomaticChecks is explicitly false, auto-updates are
disabled.
- When 'auto-update' is set, use its value to set Sparkle's auto-update
behavior.
This fixes https://github.com/ghostty-org/ghostty/issues/3535 .
There exists an issue in ghostty on mac where if you have hidden your
titlebar, then enter fullscreen, the titlebar will reappear after
exiting fullscreen.
The reason for this is that after exiting fullscreen macos reapplies
some styling on the new window created after exiting fullscreen. To
combat this we will reapply the styling to hide the titlebar after
exiting fullscreen.
Required config:
```
macos-titlebar-style = hidden
macos-non-native-fullscreen = true
```
Steps to reproduce:
- Open Ghostty
- Enter fullscreen (non-native)
- Exit fullscreen
On main you will see the titlebar reappearing after exiting fullscreen,
while that does not happen with this patch.
This fixes https://github.com/ghostty-org/ghostty/issues/3535 .
There exists an issue in ghostty on mac where if you have hidden your
titlebar, then enter fullscreen, the titlebar will reappear after
exiting fullscreen.
The reason for this is that after exiting fullscreen macos reapplies
some styling on the new window created after exiting fullscreen. To
combat this we will reapply the styling to hide the titlebar after
exiting fullscreen.
Required config:
```
macos-titlebar-style = hidden
macos-non-native-fullscreen = true
```
Steps to reproduce:
- Open Ghostty
- Enter fullscreen (non-native)
- Exit fullscreen
On main you will see the titlebar reappearing after exiting fullscreen,
while that does not happen with this patch.
Commit ad503b8c4f ("linux: consider Xft.dpi to scale the content")
introduced reading gtk-xft-dpi when the X11 build option is enabled.
While the name suggests it is X11-specific (perhaps it was at one
point), gtk-xft-dpi is a GTK setting that can be modified regardless of
GDK backend. GNOME’s Large Text accessibility setting ultimately
modifies it. Outside of desktop environments, it can be set via GTK
configuration files.
Remove the conditional gating the code on X11, since none of the code is
actually X11-specific. While we’re here, document scaling behaviors
under Config.font-size.
Fixes: ad503b8c4f ("linux: consider Xft.dpi to scale the content")
Fixes: https://github.com/ghostty-org/ghostty/issues/4338
Link: https://docs.gtk.org/gtk4/class.Settings.html
Link: https://docs.gtk.org/gtk4/property.Settings.gtk-xft-dpi.html
## Description:
Use proper platform-specific methods to determine cache directory paths:
1. First check `XDG_CACHE_HOME` environment variable
2. On macOS:
- Use `NSFileManager.URLForDirectory` to get system cache path
(`~/Library/Caches`)
- Use bundle ID (`com.mitchellh.ghostty`) as base directory to follow
macOS conventions
3. Fall back to XDG spec defaults for other platforms (`~/.cache`)
## Changes:
- Extract common NSFileManager path lookup logic into `makeCommonPath`
helper
- Use `NSFileManager.URLForDirectory` to get proper macOS cache
directory
- Use bundle ID for macOS cache directory to match system conventions
and `appSupportDir` behavior
- Follows the [same pattern as our configuration file
path](https://ghostty.org/docs/config#macos-specific-path-(macos-only):)
(`~/Library/Application Support/com.mitchellh.ghostty/config`)
- Aligns with `appSupportDir` implementation which already uses bundle
ID
- Add tests to verify path construction for different platforms
## Questions for reviewers:
1. Should we add migration logic for existing cache files?
2. Or should we document this as a breaking change and let users
manually clean up?
## Testing:
1. Added unit tests for path construction:
- macOS: verifies `~/Library/Caches/com.mitchellh.ghostty` path
- Linux: verifies `~/.cache/ghostty` path (XDG spec)
2. Verified tests pass with `zig build test`
Fixes#3202
Commit ad503b8c4f ("linux: consider Xft.dpi to scale the content")
introduced reading gtk-xft-dpi when the X11 build option is enabled.
While the name suggests it is X11-specific (perhaps it was at one
point), gtk-xft-dpi is a GTK setting that can be modified regardless of
GDK backend. GNOME’s Large Text accessibility setting ultimately
modifies it. Outside of desktop environments, it can be set via GTK
configuration files.
Remove the conditional gating the code on X11, since none of the code is
actually X11-specific. While we’re here, document scaling behaviors
under Config.font-size.
Fixes: ad503b8c4f ("linux: consider Xft.dpi to scale the content")
Fixes: https://github.com/ghostty-org/ghostty/issues/4338
Link: https://docs.gtk.org/gtk4/class.Settings.html
Link: https://docs.gtk.org/gtk4/property.Settings.gtk-xft-dpi.html
On non-MacOS desktop environments (Windows, Gnome, KDE, Xfce, VS Code,
...), `ctrl+ins` and `shift+ins` are system-wide alternate keybindings
(except for terminals) for `Copy` and `Paste` respectively. This PR
explicitly defines them as such in Ghostty's default keybindings.
Using `ctrl+ins` as an alt-keybinding for `Copy` allows
static/context-unaware remapping of `Copy` to `cmd+c` for Linux systems
using Mac keyboards via
[keyd](https://github.com/NixOS/nixpkgs/issues/137698#issuecomment-2404192700);
with the default `ctrl+shift+c` keybinding for copy this is basically
impossible (because that binding only applies to terminals).
Renames the top/bottom directions of `goto_split` to up/down. I have
tested this on linux (nixos) but given that `goto_split` is broken on
linux anyway (#2866) there's not a whole lot to test.
I have no way to build on macOS so I can't verify that I've changed
everything correctly for that.
Closes#3237
This way non-flake users can access packages with niv or npins easily,
and as flake-compat is already a dependency, this is just a "glue".
Copy-pasted from
[here](ff81ac966b (usage)).
An example with npins would be:
`npins add github ghostty-org ghostty`
and then in the config:
```nix
{pkgs, ...}: let
sources = import ./npins;
ghostty = import sources.ghostty;
in {
environment.systemPackages = [ ghostty.packages.${pkgs.system}.default ];
}
```
A simple change to make the text preview in the paste confirmation
dialog monospace; this feels like something that most users would want,
or at least very few users would dislike.
We just call `gtk_text_view_set_monospace` and let GTK use whatever
default monospace font it wants to use. Theoretically we could probably
tell it to use whatever font the user has configured, but this should be
sufficient for most users.
+ much more flexible syntax and lenient parser
+ allows comma-separated list as a single config value
This allows, e.g. `cv01 = 2` to select the second variant of `cv01`.
macOS bitmap-only fonts are a poorly documented format, which are often
distributed as `.dfont` or `.dfon` files. They use a 'bhed' table in
place of the usual 'head', but the table format is byte-identical, so
enabling the use of bitmap-only fonts only requires us to properly fetch
this table while calculating metrics.
ref: https://fontforge.org/docs/techref/bitmaponlysfnt.html
Reverts #3550 for obvious reasons, and may close issue #2168 because
this should now mean that bitmap fonts are properly supported under both
font backends due to #3837 - unless `otb` fonts are still not properly
supported under FreeType (they are not supported under CoreText because
CoreText does not know how to handle them).
I tested this change with the `.dfont` distribution of
[Cozette](https://github.com/slavfox/Cozette) v1.25.2 and saw no visual
issues.
macOS bitmap-only fonts are a poorly documented format, which are often
distributed as `.dfont` or `.dfon` files. They use a 'bhed' table in
place of the usual 'head', but the table format is byte-identical, so
enabling the use of bitmap-only fonts only requires us to properly fetch
this table while calculating metrics.
ref: https://fontforge.org/docs/techref/bitmaponlysfnt.html
On my system (pop-os 22.04 LTS) with system theme and seperate light and
dark themes, ghostty always defaults to light mode. Switches between
light and dark mode are properly handled.
In the logs this error is reported:
error(gtk): unable to get current color scheme:
GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such method
“ReadOne”
The spec notes that the other functions are "[Deprecated, use ReadOne
instead.](https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html)"
so using ReadOne is cerainly the correct path.
I've managed to fix this on my system by checking for the error and
falling back to an implementation using the deprecated Read.
Discussion: https://github.com/ghostty-org/ghostty/discussions/3704
Issue: https://github.com/ghostty-org/ghostty/issues/4038
## Description
Fix an issue where `write_selection_file` would create empty files when
selecting multiple lines. This occurred because the selection
coordinates were not properly ordered when writing to file.
## Problem
When selecting multiple lines from bottom to top , the resulting file
would be empty. This happened because:
1. Selection coordinates were used directly without proper ordering
2. `start()` and `end()` don't guarantee top-to-bottom, left-to-right
ordering
## Solution
Use `topLeft()` and `bottomRight()` methods to ensure correct coordinate
ordering when writing selection to file.
## Testing
Tested the following scenarios:
- Selecting multiple lines from top to bottom ✅
- Selecting multiple lines from bottom to top ✅
## Known Behavior
When selecting a single word, the entire line containing that word is
written to the file. This is consistent with the current terminal
behavior as noted in the [original
discussion](https://github.com/ghostty-org/ghostty/discussions/3594).
Fixesghostty-org/ghostty#3594
When writing selected text to file, use `topLeft` and `bottomRight` instead of
`start` and `end` to ensure correct coordinate ordering. This fixes an issue
where selection files could be empty when selecting text in reverse order.
- Use `terminal.Selection.topLeft()` for start coordinate
- Use `terminal.Selection.bottomRight()` for end coordinate
~~When processing toggle_fullscreen actions, multiple FullscreenStyle
derived objects would register observers on the same window and
subsequently remove them when the old style was deinited.~~
~~This change passes ownership of the fullscreenNotification observers
to TerminalController while still allowing FullscreenStyles access to
the window for style specific actions.~~
We need to have at least one fullscreen style (even if it is not being
used) to make sure that observers for fullscreen state changes are set
up. An alternative approach would be the first version of this PR (for
which my reasoning was wrong but the end change was correct) which
registers the fullscreen observers at either the TerminalController or
BaseTerminalController level.
Fixes#3553
Fixes#3953Fixes#3284
This fixes two issues. In fixing one issue, the other became apparent so
I fixed both in this one commit.
The first issue is that on macOS, the `open` command should take the
`-t` flag to open text files in a text editor. To do this, the `os.open`
function now takes a type hint that is used to better do the right
thing.
Second, the order of the paths that we attempt to open when editing a
config on macOS is wrong. Our priority when loading configs is well
documented:
https://ghostty.org/docs/config#macos-specific-path-(macos-only). But
open_config does the opposite. This makes it too easy for people to have
configs that are being overridden without them realizing it.
This commit changes the order of the paths to match the documented
order. If neither path exists, we prefer AppSupport.
We refresh the link hover state in two (generic) cases
1. When the modifiers change
2. When the cursor changes position
Each of these have additional state qualifiers. Modify the qualifiers
such that we refresh links under the following scenarios:
1. Modifiers change
- Control is pressed (this is handled in the renderer)
- Mouse reporting is off
OR
Mouse reporting is on AND shift is pressed AND we are NOT reporting
shift to the terminal
2. Cursor changes position
- Control is pressed (this is handled in the renderer)
- We previously were over a link
- The position changed (or we had no previous position)
- Mouse reporting is off
OR
Mouse reporting is on AND shift is pressed AND we are NOT reporting
shift to the terminal
This fixes a few issues with the previous implementation:
1. If mouse reporting was on and you were over a link, pressing ctrl
would enable link hover state. If you moved your mouse, you would
exit that state. The logic in the keyCallback and the
cursorPosCallback was not the same. Now, they both check for the same
set of conditions
2. If mouse reporting was off, you could hold control and move the mouse
to discover links. If mouse reporting was on, holding control + shift
would not allow you to discover links. You had to be hovering one
when you pressed the modifiers. Previously, we only refreshed links
if we *weren't* reporting the mouse event. Now, we refresh links even
even if we report a mouse event (ie a mouse motion event with the
shift modifier pressed *will* hover links and also report events)
## Old Behavior
Notice that the state of the hyperlink is erratic in `comlink`. When I
am over it and press ctrl the link is underlined and the url hint in the
lower left shown for one frame, but then the state is dropped.
https://github.com/user-attachments/assets/52d6a8c8-8459-4d67-85eb-5d91f9833771
## New Behavior
State is retained when holding ctrl+shift. And the link only underlines
if I press both ctrl+shift. If I move the mouse around while holding
these keys, I can discover new links.
https://github.com/user-attachments/assets/78fa8e97-eb0c-4618-bd96-fe40d6bc67ce
The previous approach to wrapping `sudo` had a few shortcomings:
1. We were (re)defining our 'sudo' function wrapper in the "precmd"
path. It only needs to be defined once in the shell session.
2. If there was an existing 'sudo' alias, the function definition would
conflict and result in a syntax error.
Fix (1) by hoisting the 'sudo' function into global scope. I also
considered only defining our wrapper if an executable `sudo` binary
could be found (e.g. `-x $(builtin command -v sudo)`, but let's keep the
existing behavior for now. This allows for a `sudo` command to be
installed later in the shell session and still be wrapped.
Address (2) by defining the wrapper function using `function sudo`
(instead of `sudo()`) syntax. An explicit function definition won't
clash with an existing 'sudo' alias, although the alias will continue to
take precedence (i.e. our wrapper won't be called). If the alias is
defined _after_ our 'sudo' function is defined, our function will call
the aliased command.
This ordering is relevant because it can result in different behaviors
depending on when a user defines their aliases relative to sourcing the
shell integration script. Our recommendation remains that users either
use automatic shell injection or manually source the shell integration
script _before_ other things in their `.bashrc`, so that aligns with the
expected behavior of the 'sudo' wrapper with regard to aliases. Given
that, I don't think we need any more explicit user-facing documentation
on this beyond the script-level comments.
Fixes#3953Fixes#3284
This fixes two issues. In fixing one issue, the other became apparent so
I fixed both in this one commit.
The first issue is that on macOS, the `open` command should take the
`-t` flag to open text files in a text editor. To do this, the `os.open`
function now takes a type hint that is used to better do the right
thing.
Second, the order of the paths that we attempt to open when editing a
config on macOS is wrong. Our priority when loading configs is well documented:
https://ghostty.org/docs/config#macos-specific-path-(macos-only). But
open_config does the opposite. This makes it too easy for people to have
configs that are being overridden without them realizing it.
This commit changes the order of the paths to match the documented
order. If neither path exists, we prefer AppSupport.
The comptime path of the GTK `atLeast()` version function fails to take
the proceeding portion of the version into account. For example version
5.1.0 is incorrectly marked as less than 4.16.7 due to the minor version
(1) being less than the minor we are comparing against (16).
This update required that the major versions be equal when comparing
minor versions and the major and minor versions be equal when comparing
micro versions.
For example, building against GTK 4.17.1:
Before: version.atLeast(4,16,2) -> false
After: version.atLeast(4,16,2) -> true
# Description
The following code is causing an infinite loop that causes a CPU spikes
until the quick terminal is displayed:
87bd0bb744/macos/Sources/Features/QuickTerminal/QuickTerminalController.swift (L314-L317)
## Reproduce steps
1. Open Ghostty.
2. Open the Quick Terminal.
3. Close the Quick Terminal.
4. Reload the configuration (Ghostty > Reload Configuration or
`shift+cmd+,`).
5. Observe CPU spike.
## Fix
Now, `syncAppearance` doesn't postpone the process until it can be
consumed, and the appearance is synchronized once the animation is done
and the quick terminal is visible.
Fixes#3998
The previous approach to wrapping `sudo` had a few shortcomings:
1. We were (re)defining our 'sudo' function wrapper in the "precmd"
path. It only needs to be defined once in the shell session.
2. If there was an existing 'sudo' alias, the function definition would
conflict and result in a syntax error.
Fix (1) by hoisting the 'sudo' function into global scope. I also
considered only defining our wrapper if an executable `sudo` binary
could be found (e.g. `-x $(builtin command -v sudo)`, but let's keep the
existing behavior for now. This allows for a `sudo` command to be
installed later in the shell session and still be wrapped.
Address (2) by defining the wrapper function using `function sudo`
(instead of `sudo()`) syntax. An explicit function definition won't
clash with an existing 'sudo' alias, although the alias will continue to
take precedence (i.e. our wrapper won't be called). If the alias is
defined _after_ our 'sudo' function is defined, our function will call
the aliased command.
This ordering is relevant because it can result in different behaviors
depending on when a user defines their aliases relative to sourcing the
shell integration script. Our recommendation remains that users either
use automatic shell injection or manually source the shell integration
script _before_ other things in their `.bashrc`, so that aligns with the
expected behavior of the 'sudo' wrapper with regard to aliases. Given
that, I don't think we need any more explicit user-facing documentation
on this beyond the script-level comments.
Before this change, there seemed to be some artifacting in the window
corners due to the window border no longer outlining the content
properly. By detecting the situation, we can turn the window border
radius off.
Before this change, there seemed to be some artifacting in the window
corners due to the window border no longer outlining the content
properly. By detecting the situation, we can turn the window border
radius off.
Signed-off-by: Tristan Partin <tristan@partin.io>
If a blur radius config value was previously set but then removed or set
to 0, the new blur radius would not take effect on config reload due to
the early return clause.
The comptime path of the GTK `atLeast()` version function fails to take
the preceeding portion of the version into account. For example version
5.1.0 is incorrectly marked as less than 4.16.7 due to the minor version
(1) being less than the minor we are comparing against (16).
For example, building against GTK 4.17.1:
Before: version.atLeast(4,16,2) -> false
After: version.atLeast(4,16,2) -> true
Fixes#3202
Two changes to get here:
1. Do not fail startup if crash reporting initialization fails. This is
a non-critical feature and should not prevent the terminal from
starting.
2. Avoid freeing Sentry transport on error path. This segfaults.
Upstream issue will be reported separately.
Fixes#3202
Two changes to get here:
1. Do not fail startup if crash reporting initialization fails. This is a
non-critical feature and should not prevent the terminal from starting.
2. Avoid freeing Sentry transport on error path. This segfaults.
Upstream issue will be reported separately.
The auto-update prompt isn't useful for local (source) builds. Disable
it by default by setting Sparkle's SUEnableAutomaticChecks Info.plist
key to NO (false) for all build configurations.
We then selectively re-enable it by deleting that Info.plist key from
our release workflows. We delete the key instead of setting its value to
YES (true) to give us Sparkle's default behavior of prompting the user
to enable update checks on the second application launch. (YES tells
Sparkle to skip that prompt and silently enable update checks.)
See also: https://sparkle-project.org/documentation/customization/
(This is a safer alternative to #3273.)
Fixes: #3179
Continuing from #3043 I agree that it seems idiomatic to have an archive
with format <name>-<version>.tar.gz and matching prefix for packaging,
RPM and Debian packaging guides seem to assume this format and the
automated extract tooling assumes it too.
# Testing
I haven't tested running this workflow, and am unsure about the yaml
substitution at lines 105-106
# Breaking changes
This would break existing packaging scripts, not sure how we want to
version it
The auto-update prompt isn't useful for local (source) builds. Disable
it by default by setting Sparkle's SUEnableAutomaticChecks Info.plist
key to NO (false) for all build configurations.
We then selectively re-enable it by deleting that Info.plist key from
our release workflows. We delete the key instead of setting its value to
YES (true) to give us Sparkle's default behavior of prompting the user
to enable update checks on the second application launch. (YES tells
Sparkle to skip that prompt and silently enable update checks.)
See also: https://sparkle-project.org/documentation/customization/
The auto-update prompt isn't useful for local (source) builds so disable
both update checks and automatic downloads for the Debug and Release
configurations.
Fixes#3179
The renderer must track if the foreground, background, and cursor colors
are explicitly set by an OSC so that changes are not overridden when the
config file is reloaded.
Fixes: https://github.com/ghostty-org/ghostty/issues/2795
https://github.com/ghostty-org/ghostty/pull/3130 do over. Github seems
to have lost track of the fork status for the previous work. (perhaps
permissions?). Rebased the PR to main as I can't see why it could
possibly fail.
<details>
<summary>Previous description</summary>
Bit of a rabbit hole came up while trying to package ghostty for nixos.
zig build test would just hang when run as part of checkPhase in a nix
build. (rather than the nix develop ... command run in CI).
Here's what I understand so far:
/usr/bin/env does not exist in a nix build sandbox. This only works as a
test binary when running in nix develop as it shares its environment
with the user where this compatibility crutch exists.
When executing Command.zig tests that reference /usr/bin/env the
eventual call to fork+execevZ will duplicate the running test process as
execevZ returns rather than dissapearing into the new exec'd process.
Duplicating a test process via fork does unexepected things. zig build
test will hang for <reasons?>. A test binary created via -Demit-test-exe
will run two copies of the test suite producing two different failure
outputs for the same test. (or ~4 copies of the test framework, one
extra for each test that fails this way)
/bin/sh can be used and an alternative test target. It isn't amazing as
it's relying on stdenv creating /bin/sh and it just existing on user
systems. Other alternatives I can think of would require build flags or
some sort of contract with packaging around what binary will exist for
the Command.zig tests.
</details>
We refresh the link hover state in two (generic) cases
1. When the modifiers change
2. When the cursor changes position
Each of these have additional state qualifiers. Modify the qualifiers
such that we refresh links under the following scenarios:
1. Modifiers change
- Control is pressed (this is handled in the renderer)
- Mouse reporting is off
OR
Mouse reporting is on AND shift is pressed AND we are NOT reporting
shift to the terminal
2. Cursor changes position
- Control is pressed (this is handled in the renderer)
- We previously were over a link
- The position changed (or we had no previous position)
- Mouse reporting is off
OR
Mouse reporting is on AND shift is pressed AND we are NOT reporting
shift to the terminal
This fixes a few issues with the previous implementation:
1. If mouse reporting was on and you were over a link, pressing ctrl
would enable link hover state. If you moved your mouse, you would
exit that state. The logic in the keyCallback and the
cursorPosCallback was not the same. Now, they both check for the same
set of conditions
2. If mouse reporting was off, you could hold control and move the mouse
to discover links. If mouse reporting was on, holding control + shift
would not allow you to discover links. You had to be hovering one
when you pressed the modifiers. Previously, we only refreshed links
if we *weren't* reporting the mouse event. Now, we refresh links even
even if we report a mouse event (ie a mouse motion event with the
shift modifier pressed *will* hover links and also report events)
Adding an overlay allows to easily change the version of `ghostty`
provided by `nixpkgs`:
```nix
pkgs = import nixpkgs {
inherit system;
overlays = [ ghostty.overlays.default ];
}
```
Then, all references to `pkgs.ghostty` would refer to this project's
package definition.
I realize I'm rolling the dice by opening a PR without a pre-approved
issue, but I'll take that chance. Feel free to close if this isn't
desired; no hard feelings!
Currently, the docs for `cursor-style-blink` have two backticks side by
side in the docs, which end up rendering as actual backticks rather than
a code-formatted blank space:
<img width="721" alt="Screenshot 2024-12-28 at 11 19 02 PM"
src="https://github.com/user-attachments/assets/295369d6-624f-4efe-a7ea-495c9fd216bb"
/>
This change puts a space between the backticks so they render as a
code-formatted space.
As a follow-up to #3477 and #3748, this eliminates the use of dlopen to
access `libX11` functions by directly linking `libX11` if X11 is
enabled. This should also fix problems with systems like NixOS and Void
Linux that have reported problems using Ghostty on X11 when using the
distribution packages.
This gives people finer-grained control over the coloring of their
window titlebars. Currently only implemented for GTK.
Signed-off-by: Tristan Partin <tristan@partin.io>
Fixes#3648
The confirm-close-surface configuration can now be set to always
ensuring a confirmation dialog is shown before closing a surface, even
if shell integration indicates no running processes.
The original version had issues converting properly and caused broken
glyphs. This version tries to be as simple as possible in order to make
it easy to understand. I haven't measured the performance but in
practice this will only happen during the first render of the glyph
after a face change (i.e. during launch or when changing font size).
I removed the sentence `See the Mac App section for more information.`
because I cannot find the relevant information. It would be great to
have a separate log file and indicate its location in the document.
For the record, I just spent 15 minute searching for the location of a
log file in the document, which is painful because the website does not
have a search button. Eventually I gave up and looked into the source
file, and finally found the following comment (btw do we really need
`sudo`?):
ca7c954712/src/main_ghostty.zig (L129-L132)
Hopefully, this commit can make other new users' lives easier!
Fix for misunderstanding in
https://github.com/ghostty-org/ghostty/issues/3400
Adds info about the MetricModifier config options that they can be used
with percentages, and links to the config option `adjust-cell-width`
that has more info
A few people were copying that snippet and were facing issues such as
"permission denied", and (after a subsequent `chmod`) "syntax error".
-----
From the [CONTRIBUTING.md]:
> Pull requests should be associated with a previously accepted issue.
I decided to ignore this for a single-word change, since creating a
discussion then waiting for it to be promoted to an issue seemed
pointless for such a minor change.
[CONTRIBUTING.md]:
https://github.com/ghostty-org/ghostty/blob/main/CONTRIBUTING.md#pull-requests-implement-an-issue
Based on both context and interaction with ghostty, "now" was intended
to be "not" in the paragraph describing the behavior of
`focus-follows-mouse` is set to `true`.
Based on both context and observed behavior, "now" was intended to be "not" in the paragraph describing the behavior of `focus-follows-mouse` is set to `true`.
Fixes#3528
**Note:**
Not sure if this is what OP requested regarding displaying user defined
shortcuts as hints, but we currently relabel all tabs, but only consider
labels for tabs from 1 to 9. Applying this simple patch should allow for
displaying shortcut hints for tabs beyond 9
<details><summary>Patch</summary>
```diff
diff --git a/macos/Sources/Features/Terminal/TerminalController.swift b/macos/Sources/Features/Terminal/TerminalController.swift
index 7fd1802d..242e5711 100644
--- a/macos/Sources/Features/Terminal/TerminalController.swift
+++ b/macos/Sources/Features/Terminal/TerminalController.swift
@@ -155,13 +155,6 @@ class TerminalController: BaseTerminalController {
tabListenForFrame = windows.count > 1
for (tab, window) in zip(1..., windows) {
- // We need to clear any windows beyond this because they have had
- // a keyEquivalent set previously.
- guard tab <= 9 else {
- window.keyEquivalent = ""
- continue
- }
-
let action = "goto_tab:\(tab)"
if let equiv = ghostty.config.keyEquivalent(for: action) {
window.keyEquivalent = "\(equiv)"
```
</details>
This looks better than the regular dark color. It also happens to match
what Ptyxis does. It does not support non-libadwaita builds.
Signed-off-by: Tristan Partin <tristan@partin.io>
## Description:
Fix `DESTDIR` handling when installing terminfo database files by using
`install_path` instead of `install_prefix`. This ensures files are
correctly installed under `$DESTDIR/$prefix` during packaging.
## Changes:
- Replace `b.install_prefix` with `b.install_path` for terminfo database
installation paths
- This change properly respects the `DESTDIR` environment variable
during installation
## Testing:
I've verified this fix by:
1. Setting `DESTDIR=/tmp/ghostty`
2. Building with:
```bash
DESTDIR=/tmp/ghostty \
zig build \
--prefix /usr \
--system /tmp/offline-cache/p \
-Doptimize=ReleaseFast \
-Dcpu=baseline
```
3. Confirming files are correctly installed to:
```
/tmp/ghostty/usr/share/terminfo/ghostty.terminfo
/tmp/ghostty/usr/share/terminfo/ghostty.termcap
```
The files are now properly installed under `$DESTDIR/$prefix` path
structure as expected.
cc @BratishkaErik - Since you suggested this fix in #3152, would you
mind reviewing this implementation?
Fixes#3152
This was originally fixed in ghostty-org/website#152, but was
accidentally reverted in
[ghostty-org/website#99795d7882a5ee47437454c7c106c2874e0406dc](99795d7882).
P.S., you might want an PR template to discourage folks from making
unsolicited PRs like this :)
P.P.S., you can write issue templates as yaml files to stop folks from
ignoring them (required fields)
I was originally looking into this issue:
https://github.com/ghostty-org/ghostty/issues/3109
When running the logic and triggering a config reload, Xcode warns us
about updating publishable properties from within the notification
callback functions:
<img width="924" alt="Screenshot 2024-12-26 at 5 46 19 PM"
src="https://github.com/user-attachments/assets/38000a09-ffad-4dda-9e2d-a37e5283ff89"
/>
I believe this is because `SurfaceView` is being used as both a bridged
NSView (inside `Surface`) and also an `ObservableObject`, so it's
possible for the notification callback to happen while a SwiftUI render
loop is occurring. The notification delivery happens on whatever thread
posted the message. The better solution long-term is likely to separate
the `ObservableObject` logic into its own class to avoid mixing with the
View logic.
The solution here is to simply move the publishable mutation out of the
current loop via `DispatchQueue.main.async`. I confirmed the warning
goes away with this, and I didn't notice any odd behavior while
reloading config changes.
An exception is raised from the elvish integration module when
`TERMINFO` is set:
```
Exception: exec: "type": executable file not found in $PATH
ghostty-integration.elv:120:60-71: if (and (not $no-sudo) (not-eq "" $E:TERMINFO) (eq file (type -t sudo))) {
ghostty-integration.elv:38:1-123:1:
```
`type` is a builtin in bash and [in
fish](https://fishshell.com/docs/current/cmds/type.html) but it does not
exist in elvish. I suspect it is here as an accidental copy/paste from
the ghostty [fish
integration](https://github.com/ghostty-org/ghostty/blob/main/src/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish#L71).
Maybe we can use the elvish
[`has-external`](https://elv.sh/ref/builtin.html#has-external) function
instead (or we could remove that check altogether).
Edit: I think this is in a merge-able state (and it would fix that
error!), but I have just converted this PR to a draft since I can see
other problems with the script. I'll give it a more thorough treatment
later and amend this PR (or also happy to merge this and do other fixes
in separate PRs).
macOS will create `.DS_Store` files in any directory it opens in Finder.
The `+list_themes` command would then list this file as a theme, and
attempt to preview it. `.DS_Store` is a binary file, and is silently
failing in the theme preview...I am on Linux and when I put a small
binary file in my user themes directory, I get a segfault. There is
something about the specific contents in `.DS_Store` that does not cause
this segfault, but lets us silently fail. We should investigate this
further - the issue is in `Config.loadFile` I believe.
In either case, we need to ignore `.DS_Store` so that it is not listed
as a theme.
From the 'CONTRIBUTING.md':
"Pull requests should be associated with a previously accepted issue. If
you open a pull request for something that wasn't previously discussed,
it may be closed or remain stale for an indefinite period of time. I'm
not saying it will never be accepted, but the odds are stacked against
you."
I understand this, and I make a PR without an issue because I feel like
this is actually binary.
On discord I've been informed the quick terminal is macOS only, and in
the documentation I don't think this is expressed, please correct me if
wrong and close this.
If it's correct and the documentation should contain it, then here's my
PR adding that information on the bottom of the section.
If the location of the added information does not fit the style
guidelines I can change it.
We do not currently support bitmap fonts in a real capacity, and they
often are missing some tables which we currently rely on for metrics,
and we don't handle the metrics calculations failing gracefully right
now.
This needs to be fixed for the fontconfig discovery mechanism as well,
so this does NOT close issue #2168 (it fixes the problem on macOS but
not linux).
This greatly alleviates the effect of #2991 since most cases I've seen
that be a problem have been the accidental loading of a bitmap font; but
the underlying issue still exists.
We do not currently support bitmap fonts in a real capacity, and they
often are missing some tables which we currently rely on for metrics,
and we don't handle the metrics calculations failing gracefully right
now.
Use `install_path` instead of `install_prefix` when installing terminfo
database files to properly respect the `DESTDIR` environment variable.
This ensures files are correctly installed under `$DESTDIR/$prefix`
when packaging.
Fixes#3152
macOS will create `.DS_Store` files in any directory it opens in Finder.
The `+list_themes` command would then list this file as a theme, and
attempt to preview it. `.DS_Store` is a binary file, and is silently
failing in the theme preview...I am on Linux and when I put a small
binary file in my user themes directory, I get a segfault. There is
something about the specific contents in `.DS_Store` that does not cause
this segfault, but lets us silently fail. We should investigate this
further - the issue is in `Config.loadFile` I believe.
In either case, we need to ignore `.DS_Store` so that it is not listed
as a theme.
Fixes: #3378
This approach uses Xcode's Info.plist preprocessing to conditionally set
`SUEnableAutomaticChecks=false` for the Debug and Release build schemes.
It is unset for the ReleaseLocal scheme.
When this Info.plist key is explicitly set to false (as it is for these
build schemes), we disable auto-updates at runtime. Otherwise, we apply
the behavior defined by our "auto-update" configuration.
The auto-update prompt isn't useful for local (source) builds so disable
both update checks and automatic downloads.
There are multiple ways we could check if we've been built for source,
but the easiest and least intrusive approach is to check the value of
the 'GhosttyCommit' Info.plist key. Because it is only set as part of
the release build process, an empty key implies that we've been build
from source.
`type` is a bash builtin and should not be used in elvish.
```
Exception: exec: "type": executable file not found in $PATH
ghostty-integration.elv:120:60-71: if (and (not $no-sudo) (not-eq "" $E:TERMINFO) (eq file (type -t sudo))) {
ghostty-integration.elv:38:1-123:1:
```
We can use the elvish `has-external` function instead.
The `Command.zig` tests reach outside the local source tree and look for
files on the host os machine. This introduces some portability issues
for the tests.
The nix build sandbox doesn't include `/usr/bin/env` making it error out
when `zig build test` runs `Command.zig` tests as part of a `nix build`.
Current ci and local development relies on `nix develop` sharing a host os
file system that includes `/usr/bin/env`.
Turns out `/tmp` and `/bin/sh` are available in the build sandbox in
nix so we swap these in to enable nixpkg builds to include testing
ghostty as part of any update cycle.
Update logic for generating `webgen_actions`.
Before the change, the following grouping was produced:
```md
## `copy_to_clipboard`
Copy and paste.
## `paste_from_clipboard`
## `paste_from_selection`
## `increase_font_size`
Increase/decrease the font size by a certain amount.
```
After the change, the following grouping is being produced
```md
## `copy_to_clipboard`
## `paste_from_clipboard`
## `paste_from_selection`
Copy and paste.
## `increase_font_size`
## `decrease_font_size`
Increase/decrease the font size by a certain amount.
```
Please note that this is my first time ever writing zig, so forgive me
violating zig best practices and feel free to make suggestions
Successor of [this](https://github.com/ghostty-org/website/pull/147) pr
in the website repo
The renderer must track if the foreground, background, and cursor colors
are explicitly set by an OSC so that changes are not overridden when the
config file is reloaded.
Duplicating a test process via fork does unexepected things.
zig build test will hang
A test binary created via -Demit-test-exe will run 2 copies of the test suite
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.