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.
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.
Fixes#9963 (we'll open new issues to track GTK and other stuff)
This adds the apprt actions necessary for key tables to be shown
visually, and adapts the macOS UI to show them.
## Demo
```
keybind = example/
keybind = example/ctrl+a=text:hello
keybind = example/ctrl+b>x=text:wow
keybind = example/ctrl+c=activate_key_table:another
keybind = example/escape=deactivate_key_table
keybind = ctrl+a=activate_key_table:example
keybind = another/
keybind = another/catch_all=deactivate_key_table
```
https://github.com/user-attachments/assets/75e94ec9-b52e-439d-b0ca-229ce533c656
**AI disclosure:** The SwiftUI view was written by AI, everything else
was manual.
This does the core implementation of #9963. This implements the config
parsing, bindings (`activate_key_table`, `activate_key_table_once`,
`deactivate_key_table` and `deactivate_all_key_tables`), and core key
handling logic so they work.
I'm not going to close the issue yet because I still want to integrate
GUI onto it so that it's clear you're in a key table (similar to the
sequence UI).
No demos or anything here because it is well explained in #9963.
Part of #9963
This adds a new special key `catch_all` that can be used in keybinding
definitions to match any key that is not explicitly bound. For example:
`keybind = catch_all=new_window` (chaos!).
`catch_all` can be used in combination with modifiers, so if you want to
catch any non-bound key with Ctrl held down, you can do: `keybind =
ctrl+catch_all=new_window`.
`catch_all` can also be used with trigger sequences, so you can do:
`keybind = ctrl+a>catch_all=new_window` to catch any key pressed after
`ctrl+a` that is not explicitly bound and make a new window!
And if you want to remove the catch all binding, it is like any other:
`keybind = catch_all=unbind`.
Part of #9963
This adds a new special key `catch_all` that can be used in keybinding
definitions to match any key that is not explicitly bound. For example:
`keybind = catch_all=new_window` (chaos!).
`catch_all` can be used in combination with modifiers, so if you want to
catch any non-bound key with Ctrl held down, you can do:
`keybind = ctrl+catch_all=new_window`.
`catch_all` can also be used with trigger sequences, so you can do:
`keybind = ctrl+a>catch_all=new_window` to catch any key pressed after
`ctrl+a` that is not explicitly bound and make a new window!
And if you want to remove the catch all binding, it is like any other:
`keybind = catch_all=unbind`.
This prevents a crash in our renderer when it is larger.
I will pair this with apprt changes so that our mac app won't ever allow
a default window larger than the screen but we should be resilient at
the renderer level as well.
Fixes#9952Fixes#9969
This fixes our `constrainToScreen` implementation to properly clamp the
window size to the visible screen its coming on as documented. Further,
this addresses the positioning problem, too.
Fixes#9952Fixes#9969
This fixes our `constrainToScreen` implementation to properly clamp the
window size to the visible screen its coming on as documented. Further,
this addresses the positioning problem, too.
This prevents a crash in our renderer when it is larger.
I will pair this with apprt changes so that our mac app won't ever allow
a default window larger than the screen but we should be resilient at
the renderer level as well.
This hides the macOS tab overview when the `escape` key is pressed.
Our solution is a bit blunt here and I don't think its right. I think we
have a first responder problem somewhere but I haven't been able to find
it and find the proper place to implement `cancel` (or equivalent) to
hide the overview. I tried implementing `cancel` in all the places I
expect the responder chain to go through but none worked.
For now let's do this since it is pretty tightly scoped!
This hides the macOS tab overview when the `escape` key is pressed.
Our solution is a bit blunt here and I don't think its right. I think we
have a first responder problem somewhere but I haven't been able to find
it and find the proper place to implement `cancel` (or equivalent) to
hide the overview. I tried implementing `cancel` in all the places I
expect the responder chain to go through but none worked.
For now let's do this since it is pretty tightly scoped!
Fixes#9957
Our `Page.getRowAndCell` uses a _page-relative_ x/y coordinate system
and we were passing in viewport x/y. This has the possibility to leading
to all sorts of bugs, including the crash found in #9957 but also simply
reading the wrong cell even in single-page scenarios.
Fixes#9957
Our `Page.getRowAndCell` uses a _page-relative_ x/y coordinate system
and we were passing in viewport x/y. This has the possibility to leading
to all sorts of bugs, including the crash found in #9957 but also simply
reading the wrong cell even in single-page scenarios.
## macOS: Re-apply custom icon after app build changes
### Summary
Fixes the regression where custom icons are not re-applied after app
updates, particularly affecting users on the tip channel.
### Problem
PR #9670 introduced caching to avoid redundantly setting the app icon on
every launch. However when Ghostty updates, the app bundle is replaced
and the custom icon is reset by macOS. Since `UserDefaults` persists
across updates, the cached icon name still matches the desired icon
name, causing the icon update to be incorrectly skipped.
This was reported by users in #9670 comments as well, that after
updating Ghostty the custom icon would disappear and require manual
re-application.
### Solution
- Track the app build number (`CFBundleVersion`) alongside the icon name
in `UserDefaults`
- Re-apply the icon if either the icon config has changed OR the build
number has changed
- Only update `UserDefaults` if `NSWorkspace.setIcon()` succeeds,
preventing false-positive caching on failure
I used `CFBundleVersion` (build number, e.g. `13509`) rather than
`CFBundleShortVersionString` (e.g. `1.2.3`) because tip builds increment
the build number with each release while the short version string
remains constant. I considered combining both but this seemed redundant.
### Related
- Fixes regression mentioned in comments on #9670
- Original issue: #9666
- Original discussion: #9665
Replaces #9785
This adds session search to the command palette on macOS. Session search
lets you jump to any running terminal based on title or working
directory. The command palette shows you the title, working directory,
and tab color (if any) to help you identify the terminal you care about.
This also enhances our command palette in general to support better
sorting, more stable sorts when keys are identical, etc.
## Demo
https://github.com/user-attachments/assets/602a9424-e182-4651-bf08-378e9c5e1616
## Future
Since this inherits the command palette infrastructure, we don't have
fuzzy search capabilities yet, but I still think this is useful already.
We should add fuzzy searching in the future.
Thanks @phaistonian for the inspiration here but I did do a full
rewrite.
**AI disclosure:** I used AI to assist with this in places, but I
understand everything and touched up almost everything manually.