From 013579cfcf57aabf4fe599db2926efc3d1b8c01c Mon Sep 17 00:00:00 2001 From: Lukas <134181853+bo2themax@users.noreply.github.com> Date: Sun, 29 Mar 2026 17:19:45 +0200 Subject: [PATCH] macOS: fix initial focus of command palette when building with Xcode 26.4 Tip works fine, but I've tried release and debug build with Xcode 26.4, it failed to focus as expected --- .../Command Palette/CommandPalette.swift | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/macos/Sources/Features/Command Palette/CommandPalette.swift b/macos/Sources/Features/Command Palette/CommandPalette.swift index 10c56f8dd..c4ba7106c 100644 --- a/macos/Sources/Features/Command Palette/CommandPalette.swift +++ b/macos/Sources/Features/Command Palette/CommandPalette.swift @@ -64,7 +64,6 @@ struct CommandPaletteView: View { @State private var query = "" @State private var selectedIndex: UInt? @State private var hoveredOptionID: UUID? - @FocusState private var isTextFieldFocused: Bool // The options that we should show, taking into account any filtering from // the query. Options with matching leadingColor are ranked higher. @@ -105,7 +104,7 @@ struct CommandPaletteView: View { } VStack(alignment: .leading, spacing: 0) { - CommandPaletteQuery(query: $query, isTextFieldFocused: _isTextFieldFocused) { event in + CommandPaletteQuery(query: $query) { event in switch event { case .exit: isPresented = false @@ -178,27 +177,13 @@ struct CommandPaletteView: View { .padding() .environment(\.colorScheme, scheme) .onChange(of: isPresented) { newValue in - // Reset focus when quickly showing and hiding. - // macOS will destroy this view after a while, - // so task/onAppear will not be called again. - // If you toggle it rather quickly, we reset - // it here when dismissing. - isTextFieldFocused = newValue - if !isPresented { + if !newValue { // This is optional, since most of the time // there will be a delay before the next use. // To keep behavior the same as before, we reset it. query = "" } } - .task { - // Grab focus on the first appearance. - // This happens right after onAppear, - // so we don’t need to dispatch it again. - // Fixes: https://github.com/ghostty-org/ghostty/issues/8497 - // Also fixes initial focus while animating. - isTextFieldFocused = isPresented - } } /// Returns a score (0.0 to 1.0) indicating how well a color matches a search query color name. @@ -234,10 +219,9 @@ private struct CommandPaletteQuery: View { var onEvent: ((KeyboardEvent) -> Void)? @FocusState private var isTextFieldFocused: Bool - init(query: Binding, isTextFieldFocused: FocusState, onEvent: ((KeyboardEvent) -> Void)? = nil) { + init(query: Binding, onEvent: ((KeyboardEvent) -> Void)? = nil) { _query = query self.onEvent = onEvent - _isTextFieldFocused = isTextFieldFocused } enum KeyboardEvent { @@ -280,6 +264,17 @@ private struct CommandPaletteQuery: View { .onExitCommand { onEvent?(.exit) } .onMoveCommand { onEvent?(.move($0)) } .onSubmit { onEvent?(.submit) } + .onAppear { + // Grab focus on the first appearance. + // Debug and Release build using Xcode 26.4, + // has same issue again + // Fixes: https://github.com/ghostty-org/ghostty/issues/8497 + // SearchOverlay works magically as expected, I don't know + // why it's different here, but dispatching to next loop fixes it + DispatchQueue.main.async { + isTextFieldFocused = true + } + } } } }