When a grapheme expands to width 2 at the screen edge, this path can
write spacer_head before printWrap() sets row.wrap. With an active
hyperlink, printCell triggers hyperlink bookkeeping and page integrity
checks in that intermediate state, causing UnwrappedSpacerHead.
Mark row.wrap before writing spacer_head in this grapheme-wrap path to
keep the intermediate state valid.
When a grapheme expands to width 2 at the screen edge, this path can write
spacer_head before printWrap() sets row.wrap. With an active hyperlink,
printCell triggers hyperlink bookkeeping and page integrity checks in that
intermediate state, causing UnwrappedSpacerHead.
Mark row.wrap before writing spacer_head in this grapheme-wrap path to keep
the intermediate state valid.
This fixes an error if the script was sourced a second time:
bash: __ghostty_ps0: readonly variable
Because this is a non-exported variable, this would only happen if the
script was sourced multiple times in the same bash session.
If an existing PROMPT_COMMAND was a string ending in ; (and maybe some
spaces), we'd add a redundant ;, resulting in a syntax error. Now we
strip any trailing `;[[:space:]]*` characters from the original string
before add ours.
This fixes an error if the script was sourced a second time:
bash: __ghostty_ps0: readonly variable
Because this is a non-exported variable, this would only happen if the
script was sourced multiple times in the same bash session.
If you have multiple splits and start searching naturally the focus
transfers over to the search widget which would apply the unfocused
options. This could make it difficult to view your matches from
searching without re-focusing the surface.
This was discovered when I tested
https://github.com/ghostty-org/ghostty/discussions/11218 (which is a
different issue)
Add `aid=$pid` to 133;A and 133;D for nested shell tracking, and fix the
state comparison which was incorrectly using `constantly` (comparing a
string to a function, which always evaluated to true).
OSC 133;B (input start) and 133;P;k=r (right prompt) cannot be reliably
implemented at the script level because Elvish escapes control
characters in prompt function output, and writing directly to /dev/tty
has timing issues because Elvish renders its prompts on a background
thread. Full semantic prompt support requires a native implementation:
https://github.com/elves/elvish/pull/1917
See: #10523
Add `aid=$pid` to 133;A and 133;D for nested shell tracking, and fix the
state comparison which was incorrectly using `constantly` (comparing a
string to a function, which always evaluated to true).
OSC 133;B (input start) and 133;P;k=r (right prompt) cannot be reliably
implemented at the script level because Elvish escapes control
characters in prompt function output, and writing directly to /dev/tty
has timing issues because Elvish renders its prompts on a background
thread. Full semantic prompt support requires a native implementation:
https://github.com/elves/elvish/pull/1917
See: #10523
This is an update to address common agentic issues I run into,
but the `build.nu` script may be generally helpful to people using
the Nix env since `xcodebuild` is broken by default in Nix due to the
compiler/linker overrides Nix shell does.
I encountered an issue related to
https://github.com/ghostty-org/ghostty/discussions/8641 and
https://github.com/ghostty-org/ghostty/pull/8647, but in `zsh` instead
of `bash`.
One of my aliases is:
```bash
alias sudo='sudo '
```
Which causes following error when sourcing the zsh shell integrations:
```shell
source /usr/share/ghostty/shell-integration/zsh/ghostty-integration
/usr/share/ghostty/shell-integration/zsh/ghostty-integration:149: defining function based on alias `sudo'
/usr/share/ghostty/shell-integration/zsh/ghostty-integration:233: parse error near `()'
```
Fixes#11177
Use per-search Oniguruma match params (retry_limit_in_search) in
StringMap-backed link detection to avoid pathological backtracking hangs
on very long lines.
The units are ticks in the internal loop so its kind of opaque but this
seems to still match some very long URLs. The test case in question was
a 169K character line (which is now rejected).
Fixes#11177
Use per-search Oniguruma match params (retry_limit_in_search) in
StringMap-backed link detection to avoid pathological backtracking hangs
on very long lines.
The units are ticks in the internal loop so its kind of opaque but
this seems to still match some very long URLs. The test case in question
was a 169K character line (which is now rejected).
Fixes: #8862Fixes: #10716
This adds the machinery to pass configuration settings received over
DBus down to the GObject Surface so that that configuration information
can be used to override some settings from the current "live" config
when creating a new window. Currently it's only possible to override
`--working-directory`, `--command`, and `--title`. `-e` on the `ghostty
+new-window` CLI works as well.
Adding more overridable settings is possible, but being able to fully
override any possible setting would better be served with a major revamp
of how Ghostty handles configs, which is way out of scope at the moment.
Fixes#8208
Split-tree updates currently clear `tree_bin` and then wait for every surface
to become parentless before rebuilding. That leaves the split area blank for
one or more frames, which is the visible flicker during split create/close/
resize/equalize actions.
Keep the previous widget tree attached until the idle rebuild runs, then
swap in the rebuilt tree in one step. During rebuild, reuse existing
leaf widgets by detaching and reparenting them into the new `GtkPaned`
hierarchy instead of recreating wrappers for every leaf.
This removes the parent-settling rebuild path and avoids transient blank
frames while preserving debounced rebuild behavior.
As discussed in Discord, this commit drops the `ConfigOverride` object
in favor of a simpler method of passing the overrides around. Completely
avoiding changes to the core wasn't possible but it's very minimal now.
Fixes: #8862Fixes: #10716
This adds the machinery to pass configuration settings received over
DBus down to the GObject Surface so that that configuration information
can be used to override some settings from the current "live" config
when creating a new window. Currently it's only possible to override
`--working-directory` and `--command`. `-e` on the `ghostty +new-window`
CLI works as well.
Adding more overridable settings is possible, but being able to fully
override any possible setting would better be served with a major
revamp of how Ghostty handles configs, which I is way out of scope at
the moment.
## Summary
This PR aligns split-pane click behavior across macOS and GTK when focus
changes due to click.
When a left-click is used to transfer focus (window activation or
switching to another split), Ghostty now treats that click as focus-only
and suppresses forwarding mouse press/release events for that
focus-transfer click.
## Changes
1. macOS: suppress focus-transfer left mouse-down and matching mouse-up
in `SurfaceView_AppKit.swift`.
1. GTK: suppress focus-transfer left mouse-down and matching mouse-up in
`src/apprt/gtk/class/surface.zig`.
1. macOS: defer key-window focus sync to next runloop tick to reduce
transient focus churn in `BaseTerminalController.swift`.
1. macOS build/lint: exclude generated/dependency paths from SwiftLint
during build in `.swiftlint.yml` and
`Ghostty.xcodeproj/project.pbxproj`.
## Behavior
1. Focus-transfer split clicks are now focus-only on both macOS and GTK.
1. Matching release is also suppressed for those clicks, avoiding
release-without-press sequences.
1. Platform behavior is consistent for split focus transitions.
## Validation
1. Built macOS target with `xcodebuild -target Ghostty -configuration
Debug -arch arm64`.
1. Ran targeted Zig test command `zig build test
-Dtest-filter=computeFraction`.
1. Ran format/lint for touched files (`swiftlint lint --fix`, `zig
fmt`).
4. Build and (human) tested click scenarios on macOS
## AI Disclosure
AI-assisted.
Thread:
https://ampcode.com/threads/T-019cb9fe-b11b-753f-99e7-8ecc52b73ec4
In our multiline prompt logic, skip the newline immediately after the
first mark to avoid introducing a double newline due to OSC 133;A's
fresh-line behavior.
Fixes: #11003
Emit semantic prompt markers at line-init if PS1 doesn't contain our
marks. This ensures the terminal sees prompt markers even if another
plugin (like zinit or oh-my-posh) regenerated PS1 after our precmd ran.
We use 133;P instead of 133;A to avoid fresh-line behavior which would
disrupt the display since the prompt has already been drawn. We also
emit 133;B to mark the input area, which is needed for click-to-move.
Fixes: #10572, #10555
Emit semantic prompt markers at line-init if PS1 doesn't contain our
marks. This ensures the terminal sees prompt markers even if another
plugin (like zinit or oh-my-posh) regenerated PS1 after our precmd ran.
We use 133;P instead of 133;A to avoid fresh-line behavior which would
disrupt the display since the prompt has already been drawn. We also
emit 133;B to mark the input area, which is needed for click-to-move.
Fixes: #10555
In our multiline prompt logic, skip the newline immediately after the
first mark to avoid introducing a double newline due to OSC 133;A's
fresh-line behavior.
Fixes: #11003
Extends the macOS bell implementation to support the `audio` bell
feature by playing a user-specified audio file via NSSound.
Previously, macOS only supported the `system` feature (NSSound.beep()).
This change adds support for:
- `audio` bell feature: plays the file at `bell-audio-path` using
NSSound, respecting the `bell-audio-volume` setting
- Adds `cval()` to the `Path` type so it can be returned via the C API
Also removes the "(GTK only)" restriction from `bell-audio-path` and
`bell-audio-volume` documentation, as these options now work on macOS.
Example config:
bell-features = audio
bell-audio-path = /System/Library/Sounds/Glass.aiff
bell-audio-volume = 0.8
Because of the global shared state that FontConfig maintains, FontConfig
must be linked dynamically to the same system FontConfig shared library
that GTK uses. Ghostty's default has been changed to always link to the
system FontConfig library on non-macOS systems. If that is overridden
(by specifying `-fno-sys=fontconfig` during the build) Ghostty may crash
when trying to locate glyphs that are not available in the default font.
Fixes#10432
When the kitty keyboard protocol "report all keys as escape codes" mode
was active, composed/IME text (e.g. from dead keys or compose sequences)
was silently dropped.
This happened because the composed text is sent within our GTK apprt
with key=unidentified and no unshifted_codepoint, so no kitty entry was
found and the encoder returned without producing any output. The
plain-text fallback was also skipped because report_all bypasses it.
Send composed text as raw UTF-8 when no kitty entry is found, matching
the behavior of Kitty on Linux for me.
Fixes#10049