Repository navigation
Cmd+[ / Cmd+] traverse the global workspace focus history like the titlebar arrows #9299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -783,6 +783,17 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent | |
| var ghosttyGotoSplitDownShortcut: StoredShortcut? | ||
| private var ghosttyGotoSplitPreviousShortcut: StoredShortcut? | ||
| private var ghosttyGotoSplitNextShortcut: StoredShortcut? | ||
|
|
||
| #if DEBUG | ||
| /// Test seam: unit tests can install the mirrored Ghostty | ||
| /// goto_split:previous/next triggers without loading a Ghostty config | ||
| /// (Ghostty's macOS defaults put them on ⌘[ / ⌘], colliding with the | ||
| /// focus-history defaults this dispatch must win). | ||
| func debugSetGhosttyGotoSplitCycleShortcuts(previous: StoredShortcut?, next: StoredShortcut?) { | ||
| ghosttyGotoSplitPreviousShortcut = previous | ||
| ghosttyGotoSplitNextShortcut = next | ||
| } | ||
| #endif | ||
|
Comment on lines
+786
to
+796
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win Remove the test-only seam from the production source.
As per path instructions, 🤖 Prompt for AI AgentsSource: Path instructions |
||
| private var browserAddressBarFocusedPanelId: UUID? | ||
| /// Owns the browser omnibar selection-repeat state machine, extracted into | ||
| /// `CmuxBrowser`. The app delegate is the composition root: it injects | ||
|
|
@@ -14036,7 +14047,18 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent | |
| return true | ||
| } | ||
|
|
||
| if matchesGhosttyGotoSplitPreviousShortcut(event) { | ||
| // Pane focus cycling. `focusPreviousPane` / `focusNextPane` are the | ||
| // cmux-owned rebindable entries (default unbound); Ghostty's | ||
| // goto_split:previous/next triggers (⌘[ / ⌘] in Ghostty's macOS | ||
| // defaults) stay honored as a fallback so terminal-config bindings | ||
| // keep working. The Ghostty mirror must yield to a bound Focus | ||
| // Back/Forward shortcut: both default to ⌘[ / ⌘], and without the | ||
| // yield the mirror consumed the key here, cycling panes within the | ||
| // workspace while the focus-history branch below became unreachable | ||
| // (the titlebar arrows navigated globally; the shortcut never did). | ||
| if matchConfiguredShortcut(event: event, action: .focusPreviousPane) || | ||
| (matchesGhosttyGotoSplitPreviousShortcut(event) && | ||
| !ghosttyGotoSplitCycleShortcutYieldsToFocusHistory(event)) { | ||
| let routedTabs = preferredMainWindowContextForShortcutRouting(event: event)?.tabManager ?? tabManager | ||
| cmuxRememberFindSelectionBeforePanelFocusMove(tabManager: routedTabs, window: shortcutRoutingKeyWindow) | ||
| let moved = routedTabs?.cyclePaneFocus(forward: false) ?? false | ||
|
|
@@ -14052,7 +14074,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent | |
| return true | ||
| } | ||
|
|
||
| if matchesGhosttyGotoSplitNextShortcut(event) { | ||
| if matchConfiguredShortcut(event: event, action: .focusNextPane) || | ||
| (matchesGhosttyGotoSplitNextShortcut(event) && | ||
| !ghosttyGotoSplitCycleShortcutYieldsToFocusHistory(event)) { | ||
| let routedTabs = preferredMainWindowContextForShortcutRouting(event: event)?.tabManager ?? tabManager | ||
| cmuxRememberFindSelectionBeforePanelFocusMove(tabManager: routedTabs, window: shortcutRoutingKeyWindow) | ||
| let moved = routedTabs?.cyclePaneFocus(forward: true) ?? false | ||
|
|
@@ -15815,10 +15839,23 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent | |
|
|
||
| fileprivate func shouldRouteGhosttyGotoSplitCycleShortcutToTerminal(_ event: NSEvent) -> Bool { | ||
| guard event.type == .keyDown else { return false } | ||
| guard !ghosttyGotoSplitCycleShortcutYieldsToFocusHistory(event) else { return false } | ||
| return matchesGhosttyGotoSplitPreviousShortcut(event) | ||
| || matchesGhosttyGotoSplitNextShortcut(event) | ||
| } | ||
|
|
||
| /// Whether an event that matches Ghostty's mirrored goto_split:previous/next | ||
| /// trigger belongs to a bound Focus Back/Forward shortcut instead. Ghostty's | ||
| /// macOS defaults put goto_split:previous/next on ⌘[ / ⌘], the same keys as | ||
| /// cmux's focus-history defaults, and the mirror branches run earlier in the | ||
| /// dispatch, so without this yield the configured focus-history shortcut is | ||
| /// unreachable. Unbinding Focus Back/Forward hands the keys back to the | ||
| /// pane-cycle mirror. | ||
| func ghosttyGotoSplitCycleShortcutYieldsToFocusHistory(_ event: NSEvent) -> Bool { | ||
| matchConfiguredShortcut(event: event, action: .focusHistoryBack) | ||
| || matchConfiguredShortcut(event: event, action: .focusHistoryForward) | ||
| } | ||
|
|
||
| private func matchesGhosttyGotoSplitPreviousShortcut(_ event: NSEvent) -> Bool { | ||
| guard let ghosttyGotoSplitPreviousShortcut else { return false } | ||
| return matchShortcut(event: event, shortcut: ghosttyGotoSplitPreviousShortcut) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Add Khmer translations for both new shortcut labels.
Both entries omit the supported
kmlocale. Add a reviewed Khmer translation to each entry.Resources/Localizable.xcstrings#L202980-L203098: Addlocalizations.km.stringUnitforshortcut.focusNextPane.label.Resources/Localizable.xcstrings#L203575-L203693: Addlocalizations.km.stringUnitforshortcut.focusPreviousPane.label.Based on learnings and path instructions, new catalog keys must cover every locale supported by
Resources/Localizable.xcstrings, includingkm.📍 Affects 1 file
Resources/Localizable.xcstrings#L202980-L203098(this comment)Resources/Localizable.xcstrings#L203575-L203693🤖 Prompt for AI Agents
Sources: Path instructions, Learnings