When double-clicking text, first check if the position is part of a URL
using the default URL regex pattern. If a URL is detected, select the
entire URL instead of just the word.
This follows the feedback from PR #2324 to modify the selection behavior
rather than introducing a separate selectLink function. The implementation
uses the existing URL regex from config/url.zig which already handles
various URL schemes (http, https, ftp, ssh, etc.) and file paths.
The URL detection runs before the normal word selection, falling back to
selectWord if no URL is found at the clicked position.
Adds the `selection_for_search` action, with Cmd+E keybind by default.
This action inputs the currently selected text into the search
field without changing focus, matching standard macOS behavior.
End the currently active key sequence, if any, and flush the
keys up to this point to the terminal, excluding the key that
triggered this action.
For example: `ctrl+w>escape=end_key_sequence` would encode
`ctrl+w` to the terminal and exit the key sequence.
Normally, an invalid sequence will reset the key sequence and
flush all data including the invalid key. This action allows
you to flush only the prior keys, which is useful when you want
to bind something like a control key (`ctrl+w`) but not send
additional inputs.
Make clipboardRequest return bool to indicate whether the action could
be performed. For paste requests, synchronously check if the clipboard
contains text formats before starting the async read.
This allows 'performable:paste_from_clipboard' keybinds to pass through
when the clipboard contains non-text content (e.g., images), enabling
terminal applications to handle their own clipboard reading.
Changes:
- Surface.startClipboardRequest now returns bool
- paste_from_clipboard/paste_from_selection actions return the result
- GTK apprt checks clipboard formats synchronously before async read
- Embedded apprt always returns true (can't check synchronously)
- All other call sites discard the return value with _
This adds some new special case handling for key sequences when an
unbound keyboard input is received. If the current keybinding set scope
(i.e. active tables) has a `catch_all` binding that would `ignore`
input, then the entire key sequence is dropped.
Normally, when an unbound key sequence is received, Ghostty encodes it
and sends it to the running program.
This special behavior is useful for things like Vim mode which have `g>g`
to scroll to top, and a `catch_all=ignore` to drop all other input. If
the user presses `g>h` (unbound), you don't want `gh` to show up in your
terminal input, because the `catch_all=ignore` indicates that the user
wants that mode to drop all unbound input.
Two unrelated changes to polish key tables:
1. Key tables should be reset (deactivated) when teh config is reloaded.
This matches the behavior of key sequences as well, which are reset
on config reload.
2. A maximum number of active key tables is now enforced (8).
This prevents a misbehaving config from consuming too much memory
by activating too many key tables. This is an arbitrary limit we
can adjust later if needed.
This PR fixes an issue #9563 where relative file paths were not being
resolved against the terminal’s current working directory before
opening.
#### Verification
Tested with directories containing:
```
/tmp/test/test
❯ du -h .
0B ./spaces-end
0B ./with dot.
0B ./space middle
8.0K .
```
Parent directory resolution also works as expected:
```
/tmp/test/test
❯ du -h ..
0B ../test/spaces-end
0B ../test/with dot.
0B ../test/space middle
8.0K ../test
16K ..
```
@mitchellh
In your original description you mentioned that “Links should work for all situations as they do in iTerm2.”
I noticed that, for example, when running `ls`, the paths are not clickable, while they are clickable in iTerm2.
If you think this case should also be handled, I can open a separate PR for it once this one is accepted.
This was found by LLM hunting! We were not holding the lock properly
during these operations. There aren't any known cases where we can
directly attribute these races to issues but we did find at least one
consistent crash for a user when `linkAtPos` wasn't properly locked (in
another PR).
This continues those fixes.
From #9812
I'm not sure if this is the root cause of the crash in #9812 but the
LLM-discovered issue that we are not holding a lock here appears to be a
real issue. I manually traced the code paths and thought about this and
looked where we call `mouseRefreshLinks` in other places and this
appears to be a real bug.
If the BEL character is received too frequently, the GUI thread can be
starved and Ghostty will lock up and eventually crash. This PR limits
BEL handling to 1 per 100ms.
Fixes#9800.