When a user renames a surface via "Change Terminal Title" and then
uses copy_title_to_clipboard, the raw terminal title was copied
instead of the custom name.
This adds a new `copy_title` apprt action so each platform resolves
the effective title (user override or terminal-set) before copying
to clipboard.
Fixes#10345
The draw timer should only be activated in case a custom shader
is configured and the option custom-shader-animation is either always
or true. If the timer is kept alive CPU usage spiked enourmously.
Fixes#10667
The previous logic didn't detect the `e` option when it was combined
with other flags (e.g. `-ie`). This change also attempts to improve the
general readability of this code to be a bit more explicit.
bash-preexec implements support for its "precmd" and "preexec" hooks
using a combination of PROMPT_COMMAND and a DEBUG trap. The latter is
unfortunately quick slow (in a relative sense), and the overall system
is a bit more generalized than what we need for our shell integration
(e.g. supporting multiple function hooks, subshells, etc.).
Bash 4.4 introduced the PS0 variable, which is expanded and displayed by
interactive shells after reading a complete command but before executing
it. This is all we need to implement our own shell integration hooks.
In Bash 5.1, PROMPT_COMMAND can be an array variable, each element of
which can contain a command to be executed like a string PROMPT_COMMAND
variable. When adding our hook to PROMPT_COMMAND, we preserve its type
(string or array) to be minimally intrusive. This also matches direnv's
approach.
Bash 5.3 introduced support for function substitution, which is an even
more efficient way to run code from PS0, so we use that when available.
Otherwise, we use the more traditional command substitution approach.
Earlier versions of bash (such as 3.2, which still ships with macOS)
continue to use the bash-preexec path. This gives us two code paths to
maintain, but I think that's preferable to fully maintaining our own
DEBUG trap-based system for older bash versions given that bash-preexec
has proven to work reliably in those environments. We also wouldn't
unlock any other user benefits aside from removing the bash-preexec
script dependency.
See: #3724, #7734
PROMPT_COMMAND array support for introduced in bash 5.1, and it's the
preferred format moving forward. Using the string form is also fine, but
it's easy to be a modern bash citizen here, so let's do so.
bash-preexec implements support for its "precmd" and "preexec" hooks
using a combination of PROMPT_COMMAND and a DEBUG trap. The latter is
unfortunately quick slow (in a relative sense), and the overall system
is a bit more generalized than what we need for our shell integration
(e.g. supporting multiple function hooks, subshells, etc.).
Bash 4.4 introduced the PS0 variable, which is expanded and displayed by
interactive shells after reading a complete command but before executing
it. This is all we need to implement our own shell integration hooks.
In Bash 5.1, PROMPT_COMMAND can be an array variable, each element of
which can contain a command to be executed like a string PROMPT_COMMAND
variable. When adding our hook to PROMPT_COMMAND, we preserve its type
(string or array) to be minimally intrusive. This also matches direnv's
approach.
Bash 5.3 introduced support for function substitution, which is an even
more efficient way to run code from PS0, so we use that when available.
Otherwise, we use the more traditional command substitution approach.
Earlier versions of bash (such as 3.2, which still ships with macOS)
continue to use the bash-preexec path. This gives us two code paths to
maintain, but I think that's preferable to fully maintaining our own
DEBUG trap-based system for older bash versions given that bash-preexec
has proven to work reliably in those environments. We also wouldn't
unlock any other user benefits aside from removing the bash-preexec
script dependency.
See: #3724, #7734
The previous logic didn't detect the `e` option when it was combined
with other flags (e.g. `-ie`). This change also attempts to improve the
general readability of this code to be a bit more explicit.
This adds the ability to use two fingers on a touchpad to scroll left
or right on a Ghostty window to change tab pages. Uses the same basic
machinery as scrolling up and down the scrollback buffer. Scrolling
pages does not wrap around at the start or end of the tabs.
Related to #1972
The URL regex for file path detection requires paths to start with
`../`, `./`, or `/`. For bare relative paths like
`"src/config/url.zig"`, the regex could only match starting at the first
`/`, producing `"/config/url.zig"` as a result — always dropping the
first part of the path.
Fix: added a third top-level alternative to the regex. This matches bare
relative paths where:
1. The first component is word characters (possibly with dots/dashes):
`[\w][\w\-.]*\/`
2. The remaining path must contain a dot (via positive lookahead) — this
requires a file extension to avoid false positives on text like
input/output
3. Add a `(?<!\w)\/` instead of `\/` in the existing prefix group — the
standalone `/` prefix now requires that `/` is not preceded by a word
character. This prevents `"input/output"` from falsely matching
`"/output"`
Test cases added:
- src/config/url.zig → matches fully
- app/folder/file.rb:1 → matches with line number
- modified: src/config/url.zig → matches only the path part
- lib/ghostty/terminal.zig:42:10 → matches with line:col
- some-pkg/src/file.txt more text → stops before trailing text
- input/output and foo/bar → correctly do not match (no file extension)
The issue was nailed down here:
https://github.com/ghostty-org/ghostty/issues/1972#issuecomment-3845717672
We always add GHOSTTY_SHELL_INTEGRATION_XDG_DIR to XDG_DATA_DIRS with a
tailing colon (via our prependEnv routine), so we can greatly simplify
this cleanup code with a single str:replace call.
We always add GHOSTTY_SHELL_INTEGRATION_XDG_DIR to XDG_DATA_DIRS with a
tailing colon (via our prependEnv routine), so we can greatly simplify
this cleanup code with a single str:replace call.
Fixes#10522
This also fixes possible runtime safety crashes. Whenever the underlying
size information doesn't match what our renderer or grid see, then we
should deinit and reinit.
This adds support for the `OSC 133 A click_events=1` extension
introduced by Kitty and supported by Fish.[^1]
**What this means:** If the shell advertises `click_events=1` support,
Ghostty will _unconditionally_ (no modifier required) send mouse events
to the shell for clicks on a prompt line, delegating to the supporting
shell to move the cursor as needed. For Fish 4.1+ this means that
clicking on the prompt line moves the cursor (see demo video below).
This PR also contains:
* A minor fix in `cl` parsing but we don't yet implement the logic there
* Updated inspector to show the semantic prompt click mode
## Demo
https://github.com/user-attachments/assets/03ef8975-7ad9-441f-aaa2-9d0eb5c5e36d
## Implementation Details
`click_events` is wildly underspecified, so here are the details the
best I understand them. This itself is not a specification (I omit
details) but adds some more context to it.
The `click_events=1` option can be specified with `OSC 133 A` (Ghostty
also allows it on OSC 133 N). When that is specified, it flags for all
future prompts that the screen supports click events for semantic
prompts. If both `click_events` and `cl` are specified, `click_events`
takes priority if true. If `click_events=0` (disable), then any set `cl`
will take priority.
When a mouse click comes in, we check for the following conditions:
1. The screen supports click events
2. The screen cursor is currently at a prompt
3. The mouse click was at or below the starting prompt line of the
current prompt
If those are met, we encode an SGR mouse event with: left button, press,
coordinates of click. It is up to the shell after that to handle it. Out
of prompt bounds SGR events are possible (specifically below). The shell
should robustly handle this.
[^1]: I don't know any other terminal or shell that supports it at the
moment.
Wrapping `use ghostty-integration` in a `try .. catch` here makes this
suggestion more resilient to environments where we didn't inject our
resource directory into XDG_DATA_DIRS (but are still running Ghostty).
The ssh wrapper previously used a separate set_ssh_terminfo function
that returned a record to be merged, which result in some redundant
control flow and TERM assignments.
This inlines the terminfo logic and builds env/opts incrementally based
on feature flags. TERM is set to a fallback early and only overridden on
success, which simplifies our error handling and avoids mutable variable
capture issues in closures.
Lastly, warnings are now consistently written to stderr, and I made
various other control flow and syntax improvements.
Wrapping `use ghostty-integration` in a `try .. catch` here makes this
suggestion more resilient to environments where we didn't inject our
resource directory into XDG_DATA_DIRS (but are still running Ghostty).
This reporting shouldn't have been tied to the 'title' shell features.
That's a different feature where we change the window title (icon) to
reflect the current command using OSC 2.
Nu properly marks input areas with OSC 133 B, but if it spans multiple
lines it doesn't mark the continuation lines with the k=s sequence.
Our prompt redraw logic before only cleared explicitly designated prompt
lines. But if the input line is multi-line and the continuation lines
are not marked, those lines would not be cleared, leading to visual
issues on resize.
To workaround this, we assume that if the current cursor semantic
content is anything other than "command output" (default), then we're
probably at a prompt line and should clear from there all the way up.
This works around Fish (at least v4.2) having a non-compliant OSC133
implementation paired with not having the hooks to fix this via shell
integration. We have to instead resort to heuristics in the terminal
emulator. Womp, womp.
The issue is that Fish does not emit OSC133 secondary prompt (`k=s`)
markers at the beginning of continuation lines. And, since Fish doesn't
provide a PS2-equivalent, we can't do this via shell integration.
We fix this by assuming on newline (`\n`) that a cursor that is already
painting prompt cells is continuing a prior prompt line, and
pre-emptively mark it as a prompt line. But this has two further issues
we have to work around:
1. Newline/index (`\n`) is one of the _hottest path_ functions in
terminal emulation. It sucks to add any new conditional logic here.
We do our best to gate this on unlikely conditions that the branch
predictor can easily optimize away.
2. Fish also emits these for auto-complete hints that may be deleted
later. So, we also have to handle the scenario where a prompt is
continued, then replaced by command output, and fix up the prompt
continuation flag to go back to output mode.
Point 2 is ALMOST automatically handled, because Fish does emit a `CSI J`
(erase display below) to erase the auto-complete hint. This resets all
our rows back to output rows. **Unfortunately**, Fish emits `\n` before
triggering the preexec hooks which set OSC133C. So we get the newline
logic FIRST (sets the prompt line), THEN sets the output cursor. If they
switched ordering here everything would just work (with the one
heuristic). But now, we need two!
To address this, I put some extra heuristic logic in the OSC133C
(output starting) handler: if our row is marked as a prompt AND our
cursor is at x=0, we assume that the prompt continuation was deleted
and we unmark it.
I put the heuristic logic dependent on OSC133C because that's way colder
of a path than putting something in `printCell` (which is the actual
hottest path in Ghostty).
We could get more rigorous here by also checking if every cell is empty
but that doesn't seem to be necessary at this time for any Fish version
I've tested. I hope thats correct.
I'd really love for Fish to improve their OSC133 implementation to
conform more closely to the terminal-wg spec, but we're going to need
these workarounds indefinitely to handle older Fish versions anyway.
Insert OSC 133 A k=s marks after each newline in PS1, so that all lines
following the first are marked as secondary prompts. This prevents ghostty
from erasing leading lines during terminal resize.