Fixes#10424
Replaces #10431
The issue is that when the row where preedit was wasn't dirty, we were
layering more preedit cells (identical ones) on top, so it'd appear to
get "thicker".
The `cursor` shell feature always used a blinking bar (beam), often to
the surprise of users who set `cursor-style-blink = false`.
This change extends our GHOSTTY_SHELL_FEATURES format to include either
`cursor:blink` (default) or `cursor:steady` based on cursor-style-blink
when the `cursor` feature is enabled, and all shell integrations have
been updated to use that additional information to choose the DECSCUSR
cursor value (5=blinking bar, 6=steady bar).
I also considered passing a DECSCUSR value in GHOSTTY_SHELL_FEATURES
(e.g. `cursor:5`). This mostly worked well, but zsh also needs the blink
state on its own for its block cursor. We also don't support any other
shell feature cursor configurability (e.g. the shape), so this was an
over generalization.
This does change the behavior for users who like the blinking bar in the
shell but have `cursor-blink-style = false` for other reasons. We could
provide additional `cursor` shell feature configurability (e.g.
`cursor:blink` in `shell-integration-features`), but I'll propose that
as its own change.
See: #2812Closes: #8681
---
**AI Disclosure:** I did a lot of rubber ducking with Claude Code while
trying out various ideas. It was particularly useful for this kind of
feature because I could try out one thing and have it evaluate the
impact on all of the shell integration scripts at once.
Our PS1 cleanup code (where we remove any markers we added) was still
looking for the previous 133;A form. Update it to include 'cl=line',
which was added in 8595558.
Our PS1 cleanup code (where we remove any markers we added) was still
looking for the previous 133;A form. Update it to include 'cl=line',
which was added in 8595558.
We already had an established Ghostty.Shell namespace (previously a
struct; now a more idiomatic enum), and locating these functions next to
each other makes it clearer how they relate to one another.
Xcode wants these to be sorted and will update this list when the
project file is saved so proactively make this change before it gets
mixed up in other work.
We already had an established Ghostty.Shell namespace (previously a
struct; now a more idiomatic enum), and locating these functions next to
each other makes it clearer how they relate to one another.
Xcode wants these to be sorted and will update this list when the
project file is saved so proactively make this change before it gets
mixed up in other work.
## Summary
- Fixes#10345 — `copy_title_to_clipboard` now copies the user-set
custom title instead of the raw terminal title
- Adds a new `copy_title` apprt action as [suggested by
@mitchellh](https://github.com/ghostty-org/ghostty/issues/10345#issuecomment-2601002974)
- Each platform (GTK + macOS) resolves the effective title (user
override → terminal title fallback) before copying to clipboard
## Changes
- **`src/apprt/action.zig`** — New `copy_title` void action
- **`include/ghostty.h`** — C ABI enum entry
- **`src/Surface.zig`** — Binding handler now dispatches apprt action
instead of inline logic
- **`src/apprt/gtk/class/surface.zig`** — `getEffectiveTitle()` helper
(returns `title_override orelse title`)
- **`src/apprt/gtk/class/application.zig`** — GTK action handler
- **`macos/.../Ghostty.App.swift`** — macOS handler using
`surfaceView.title` + `NSPasteboard`
*Note*: This PR was *AI* assisted.
The printf was part of the original script (9d6121245), and at the time,
this was the only place we'd emit the 133;A mark.
A PS1-based 133;P;k=i mark was introduced in 2bf1f80f7, and then it
become a full 133;A mark in aa47047a6, making the original printf line
redundant (because bash will also redraw PS1 on SIGWINCH).
The PS1-based 133;A was only missing the aid= option, and with that
added, it handles all of our cases (prompts, initial draw, and resizes).
The printf was part of the original script (9d6121245), and at the time,
this was the only place we'd emit the 133;A mark.
A PS1-based 133;P;k=i mark was introduced in 2bf1f80f7, and then it
become a full 133;A mark in aa47047a6, making the original printf line
redundant (because bash will also redraw PS1 on SIGWINCH).
The PS1-based 133;A was only missing the aid= option, and with that
added, it handles all of our cases (prompts, initial draw, and resizes).
For a hardcoded set of control characters, replace them with spaces when
encoding pasted text. This is to prevent unsafe control characters from
being pasted which could trick a user into executing commands
unexpectedly.
This happens regardless of bracketed paste mode, because certain
characters processed by the kernel pty line discipline can break
bracketed paste (source from zsh:
https://zsh-workers.zsh.narkive.com/Kd3evJ7t/bracketed-paste-mode-in-xterm-and-urxvt).
This behavior is based on xterm's behavior
(caac5c35a2/button.c (L2578-L2595)),
including the list of characters. Note that as a comment in the code
says, we should be sourcing some of these from a tcgetattr call instead
of hardcoding them, but this is a good start.
For a hardcoded set of control characters, replace them with spaces when
encoding pasted text. This is to prevent unsafe control characters from being
pasted which could trick a user into executing commands unexpectedly.
This happens regardless of bracketed paste mode, because certain
characters processed by the kernel pty line discipline can break
bracketed paste (source from zsh:
https://zsh-workers.zsh.narkive.com/Kd3evJ7t/bracketed-paste-mode-in-xterm-and-urxvt).
This behavior is based on xterm's behavior, including the list of
characters. Note that as a comment in the code says, we should be
sourcing some of these from a tcgetattr call instead of hardcoding them,
but this is a good start.
Follow-up to #8445, after a messed up rebase in #8339 brought it back
alongside an extra section.
All text removed from `CONTRIBUTING.md` was identical to the version
present in `HACKING.md` (according to a textual diff), excluding the
“Developer Guide” heading, the callout under it, and the “Nix VM
Integration Tests” section introduced in #8339.
Follow-up to #8445, after a messed up rebase in #8339 brought it back
alongside an extra section.
All text removed from CONTRIBUTING.md was identical to the version
present in HACKING.md (according to a textual diff), excluding the
“Developer Guide” heading, the callout under it, and the “Nix VM
Integration Tests” section introduced in #8339.
This pull request addresses some of the remaining issues when matching
`~`, `$VAR`, `.directory/`, and embedded commas. It does not address
issues with embedded line breaks.
The PR is split in multiple commits carefully applying a set of changes
to
1. make the big regex more composable / readable
2. update some doc strings
3. add more test cases for the issues mentioned
4. two simple commits, each fixing the issues
Changes:
- **url: refactor regex into documented branches**
Break up the big monolithic URL and path regex into named sub-pattern
constants and compose the final expression from three commented
branches:
- URLs with a scheme
- absolute or dot-relative paths
- bare relative paths
This commit only breaks up the regex. It keeps the existing matching
behavior unchanged.
- **url: update top-level comment**
- **url: carefully extend test cases**
Extend existing test cases with `~`, `$VAR`, and bare .-prefixed paths
and embedded `,` comma handling.
See following issue comments:
-
https://github.com/ghostty-org/ghostty/pull/10570#issuecomment-3853842036
-
https://github.com/ghostty-org/ghostty/issues/1972#issuecomment-3859329233
-
https://github.com/ghostty-org/ghostty/issues/1972#issuecomment-3857881196
- **url: remove `,` from path_chars**
Related to #1972
Fixes an issue when paths have embedded comma, e.g.:
shared/src/foo/SomeItem.m:12, shared/src/
with path_chars greedily consuming the rest of the string.
Now file path matching stops at comma. Scheme URLs are unchanged and
still using the comma.
- **url: fix matching `~`, `$VAR`, `.directory/`**
Related to #1972
This commit adds three new alternatives for
`rooted_or_relative_path_prefix`:
- `~/`
- `$VAR` and
- `.local/`, `.config/` etc. for dot-prefixed directory names
Remaining commits fix edge cases one by one:
- **url: fix mid-string dot partial matches**
`"foo.local/share"` (was partial match) → now matches fully
- **url: fix $-numeric character matches**
`"$10/$20"` → no match
- **url: fix partial match of mid string $-variable**
`"foo/$BAR/baz"` (was partial match) → matches fully now
- **url: fix incomplete $-numeric behavior**
`"$10/bar.txt"` (was partial match) → but should not match at all
Closes#10718
## Summary
- Populates the `symbols` field on `CommandOption` by looking up
keybindings via the existing `keyboardShortcut(for:)` API
- All the UI rendering (`ShortcutSymbolsView`) and the keybinding lookup
were already in place, this just wires them together
## AI Disclosure
Claude Code was used to assist with codebase exploration and drafting
the change. The implementation was manually verified by building and
testing locally on macOS with Xcode 26.2.
## Test plan
- [x] Built with `xcodebuild` on Xcode 26.1 and 26.2
- [x] Launched app, opened command palette, confirmed shortcuts appear
next to commands that have keybindings
- [x] Confirmed commands without keybindings show no shortcuts
<img width="912" height="744" alt="Screenshot 2026-02-14 at 12 55 42 PM"
src="https://github.com/user-attachments/assets/b988015c-21b6-4a17-9883-e23c87c6934b"
/>