mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-19 14:00:29 +00:00
macOS: restore keyboard focus after inline tab title edit (#11320)
## Summary - After finishing an inline tab title edit (via keybind or double-click), all keyboard input is lost because `TabTitleEditor.finishEditing()` sets `makeFirstResponder(nil)`, leaving the window itself as first responder with no path back to the terminal surface. - Adds a `tabTitleEditorDidFinishEditing` delegate callback to `TabTitleEditorDelegate` that fires after every edit (commit or cancel). - `TerminalWindow` implements it by calling `makeFirstResponder(focusedSurface)` to restore keyboard focus to the terminal. Fixes https://github.com/ghostty-org/ghostty/discussions/11315 ## Testing - [x] Bind `prompt_tab_title` to a keybind (e.g. `keybind = cmd+shift+i=prompt_tab_title`) - [x] Trigger inline tab title edit via keybind, press Enter — verify keyboard input works immediately - [x] Trigger inline tab title edit via keybind, press Escape — verify keyboard input works immediately - [x] Double-click a tab title, press Enter — verify keyboard input works immediately - [x] Double-click a tab title, press Escape — verify keyboard input works immediately - [x] Verify Cmd+number tab switching works after all of the above - [x] Verify split pane focus is correct after editing tab title with splits open AI disclosure: Codebase exploration and review via [Claude Code](https://claude.com/claude-code)
This commit is contained in:
@@ -835,4 +835,13 @@ extension TerminalWindow: TabTitleEditorDelegate {
|
||||
guard let targetController = targetWindow.windowController as? BaseTerminalController else { return }
|
||||
targetController.promptTabTitle()
|
||||
}
|
||||
|
||||
func tabTitleEditor(_ editor: TabTitleEditor, didFinishEditing targetWindow: NSWindow) {
|
||||
// After inline editing, the first responder is the window itself.
|
||||
// Restore focus to the terminal surface so keyboard input works.
|
||||
guard let controller = windowController as? BaseTerminalController,
|
||||
let focusedSurface = controller.focusedSurface
|
||||
else { return }
|
||||
makeFirstResponder(focusedSurface)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@ protocol TabTitleEditorDelegate: AnyObject {
|
||||
_ editor: TabTitleEditor,
|
||||
performFallbackRenameFor targetWindow: NSWindow
|
||||
)
|
||||
|
||||
/// Called after inline editing finishes (whether committed or cancelled).
|
||||
/// Use this to restore focus to the appropriate responder.
|
||||
func tabTitleEditor(
|
||||
_ editor: TabTitleEditor,
|
||||
didFinishEditing targetWindow: NSWindow)
|
||||
}
|
||||
|
||||
/// Handles inline tab title editing for native AppKit window tabs.
|
||||
@@ -212,8 +218,14 @@ final class TabTitleEditor: NSObject, NSTextFieldDelegate {
|
||||
previousTabState = nil
|
||||
|
||||
// Delegate owns title persistence semantics (including empty-title handling).
|
||||
guard commit, let targetWindow else { return }
|
||||
delegate?.tabTitleEditor(self, didCommitTitle: editedTitle, for: targetWindow)
|
||||
guard let targetWindow else { return }
|
||||
|
||||
if commit {
|
||||
delegate?.tabTitleEditor(self, didCommitTitle: editedTitle, for: targetWindow)
|
||||
}
|
||||
|
||||
// Notify delegate that editing is done so it can restore focus.
|
||||
delegate?.tabTitleEditor(self, didFinishEditing: targetWindow)
|
||||
}
|
||||
|
||||
/// Chooses an editor frame that aligns with the tab title within the tab button.
|
||||
|
||||
Reference in New Issue
Block a user