The return value of takeUnretainedValue() is non-optional, so this
function was never _actually_ returning an optional value, so the guard
clauses sprinkled throughout were unnecessary.
Fixes#880
If a command is specified but it can't be found, then we try to fallback
to a default command like "sh" and log the issue. This prevents Ghostty
from simply exiting.
This enables shifted alt-prefixed keys, such as `shift+alt+.` on
US standard becoming `M->`. To do this, we needed to fix a few bugs:
(1) translation mods should strip alt even if other mods are set
(2) AppKit translation event needs to construct new characters with
the translation mods.
(3) Alt-prefix handling in KeyEncoder needs to allow ASCII utf8
translations even for macOS.
Fixes#872
In #867 we fixed macos-option-as-alt, but unfortunately AppKit ALSO does
some translation so some behaviors were not working correctly.
Specifically, when you had macos-option-as-alt set, option+e would
properly send `esc+e` to the pty but it would ALSO set the dead key
state for "`" since AppKit was still translating the option key.
This commit introduces a function to strip alt when necessary from the
translation modifiers used at the AppKit layer, preventing this
behavior.
This regressed sometime -- I can't find the exact commit -- but in any
case I've moved this handling directly into the KeyEncoder so we can
unit test it and prevent future regressions.
Fixes#865
Related to #861
In #861, we fixed a deadlock that could happen if the writer mailbox was
full from the reader thread by waking up the writer thread for
processing.
Unfortunately, the writer thread ALSO handles messages that require the
terminal lock (i.e. resizing, focus state, etc.). If the mailbox
contains these messages, it cannot make forward progress on the writes
(which do not require a lock). This makes it possible still under heavy
write scenarios to fully deadlock the read/write threads.
This commit modifies the behavior so that while we are attempting to
queue a writer message after it fails, we release the lock. This is a
very slow path since we are releasing/acquiring locks under heavy
contention. We can improve it in the future but for now its okay because
this is also a rare situation that only happens under the heaviest loads
that also produce heavy writes.
Fixes#741
This completely reimplements double-click-and-drag logic for selecting
by word. The previous implementation was horribly broken. See #741 for
all the details.
The implemented logic now is:
* A double-click initiates a select-by-word selection mechanism.
- A double-click may start on a word or whitespace
- If the initial double-click is on a word, that word is immediately selected.
- If the initial double-click is on whitespace, the whitespace is not selected.
* A "word" is determined by a non-boundary character meeting a boundary character.
- A boundary character is `NUL` ` ` (space) `\t` `'` `"`
- This list is somewhat arbitrary to make the terminal "feel" good.
- Cell SGR states (fg/bg, bold, italic, etc.) have no effect on boundary determination or selection logic.
* As the user drags _on the same line_:
- No selection change occurs until the cursor is over a new word. Whitespace change does nothing.
- When selection is over a new word, that entire word added to the selection.
* When the user drags _up_ one or more lines:
- If the cursor is over whitespace, all lines from the selection point up to but not including the cursor line are selected.
* This selection is done in accordance to the previous rules.
- If the cursor is over a word, the word becomes the beginning of the selection.
- The end of the selection in all cases is the first word at or before the initial double-click point.
* When the user drags _down_ one or more lines:
- The same logic as _up_ but swap the "beginning" and "end" of selection terminology.
* With this logic, the behavior of Ghostty has the following invariants:
- Whitespace is never selected unless it is between two selected words
- Selection implies at least one word is highlighted
- The initial double-click point marks the beginning or end of a selection, never the middle.
This fixes#786 by adding a check to the callback that unhides the menu
bar to only unhide the menu bar if focus was lost to another Ghostty
window.
That's the desired behaviour: when focus is lost to another app's
window, we want the non-native-fullscreen window to stay unchanged in
background, but when changing focus to another Ghostty window, we want
to unhide the menu bar.
Why did this problem even show up?
It started to show up with the introduction of the Xib-file based
approach, in 3018377.
Before that, in 27ddc90, for example, the app would receive the same
notifications, but the `.autoHideMenuBar` didn't have an effect on the
window. Only after adding the Xib-file did it start to have an effect.
So I figured there's two ways we could fix it:
1. Figure out why the `.autoHideMenuBar` now works with Xib-files and
suppress it, or
2. Encode in the code the behaviour that we actually want: we only want
to show the menu bar when focus shifts to another one of Ghostty's
windows, but we want to leave it untouched when focus is lost to
another app's window.
I went with (2) but I think (1) is also valid and happy to close PR if
that's what we want to do.