diff --git a/CodeEdit/Features/Documents/Controllers/CodeEditWindowController.swift b/CodeEdit/Features/Documents/Controllers/CodeEditWindowController.swift index 34543e8be..be082d6fe 100644 --- a/CodeEdit/Features/Documents/Controllers/CodeEditWindowController.swift +++ b/CodeEdit/Features/Documents/Controllers/CodeEditWindowController.swift @@ -143,6 +143,21 @@ final class CodeEditWindowController: NSWindowController, NSToolbarDelegate, Obs } } + /// Opens the search navigator and focuses the search field + @IBAction func openSearchNavigator(_ sender: Any? = nil) { + if navigatorCollapsed { + toggleFirstPanel() + } + + if let navigatorViewModel = navigatorSidebarViewModel, + let searchTab = navigatorViewModel.tabItems.first(where: { $0 == .search }) { + DispatchQueue.main.async { + self.workspace?.searchState?.shouldFocusSearchField = true + navigatorViewModel.setNavigatorTab(tab: searchTab) + } + } + } + @IBAction func openQuickly(_ sender: Any?) { if let workspace, let state = workspace.openQuicklyViewModel { if let quickOpenPanel { diff --git a/CodeEdit/Features/Documents/WorkspaceDocument/WorkspaceDocument+SearchState.swift b/CodeEdit/Features/Documents/WorkspaceDocument/WorkspaceDocument+SearchState.swift index 5d321c647..2ee8305a5 100644 --- a/CodeEdit/Features/Documents/WorkspaceDocument/WorkspaceDocument+SearchState.swift +++ b/CodeEdit/Features/Documents/WorkspaceDocument/WorkspaceDocument+SearchState.swift @@ -35,6 +35,8 @@ extension WorkspaceDocument { @Published var findNavigatorStatus: FindNavigatorStatus = .none + @Published var shouldFocusSearchField: Bool = false + unowned var workspace: WorkspaceDocument var tempSearchResults = [SearchResultModel]() var caseSensitive: Bool = false diff --git a/CodeEdit/Features/NavigatorArea/FindNavigator/FindNavigatorForm.swift b/CodeEdit/Features/NavigatorArea/FindNavigator/FindNavigatorForm.swift index 393789b09..baefe9d8c 100644 --- a/CodeEdit/Features/NavigatorArea/FindNavigator/FindNavigatorForm.swift +++ b/CodeEdit/Features/NavigatorArea/FindNavigator/FindNavigatorForm.swift @@ -25,63 +25,13 @@ struct FindNavigatorForm: View { @State private var preserveCase: Bool = false @State private var scopedToOpenEditors: Bool = false @State private var excludeSettings: Bool = true + @FocusState private var isSearchFieldFocused: Bool init(state: WorkspaceDocument.SearchState) { self.state = state selectedMode = state.selectedMode } - private func getMenuList(_ index: Int) -> [SearchModeModel] { - index == 0 ? SearchModeModel.SearchModes : selectedMode[index - 1].children - } - - private func onSelectMenuItem(_ index: Int, searchMode: SearchModeModel) { - var newSelectedMode: [SearchModeModel] = [] - - switch index { - case 0: - newSelectedMode.append(searchMode) - self.updateSelectedMode(searchMode, searchModel: &newSelectedMode) - self.selectedMode = newSelectedMode - case 1: - if let firstMode = selectedMode.first { - newSelectedMode.append(contentsOf: [firstMode, searchMode]) - if let thirdMode = searchMode.children.first { - if let selectedThirdMode = selectedMode.third, searchMode.children.contains(selectedThirdMode) { - newSelectedMode.append(selectedThirdMode) - } else { - newSelectedMode.append(thirdMode) - } - } - } - self.selectedMode = newSelectedMode - case 2: - if let firstMode = selectedMode.first, let secondMode = selectedMode.second { - newSelectedMode.append(contentsOf: [firstMode, secondMode, searchMode]) - } - self.selectedMode = newSelectedMode - default: - return - } - } - - private func updateSelectedMode(_ searchMode: SearchModeModel, searchModel: inout [SearchModeModel]) { - if let secondMode = searchMode.children.first { - if let selectedSecondMode = selectedMode.second, searchMode.children.contains(selectedSecondMode) { - searchModel.append(contentsOf: selectedMode.dropFirst()) - } else { - searchModel.append(secondMode) - if let thirdMode = secondMode.children.first, let selectedThirdMode = selectedMode.third { - if secondMode.children.contains(selectedThirdMode) { - searchModel.append(selectedThirdMode) - } else { - searchModel.append(thirdMode) - } - } - } - } - } - private var chevron: some View { Image(systemName: "chevron.compact.right") .foregroundStyle(.tertiary) @@ -152,6 +102,7 @@ struct FindNavigatorForm: View { }, hasValue: caseSensitive ) + .focused($isSearchFieldFocused) .onSubmit { if !state.searchQuery.isEmpty { Task { @@ -262,16 +213,65 @@ struct FindNavigatorForm: View { } } } + .onReceive(state.$shouldFocusSearchField) { shouldFocus in + if shouldFocus { + isSearchFieldFocused = true + state.shouldFocusSearchField = false + } + } .lineLimit(1...5) } } -extension Array { - var second: Element? { - self.count > 1 ? self[1] : nil +extension FindNavigatorForm { + private func getMenuList(_ index: Int) -> [SearchModeModel] { + index == 0 ? SearchModeModel.SearchModes : selectedMode[index - 1].children + } + + private func onSelectMenuItem(_ index: Int, searchMode: SearchModeModel) { + var newSelectedMode: [SearchModeModel] = [] + + switch index { + case 0: + newSelectedMode.append(searchMode) + self.updateSelectedMode(searchMode, searchModel: &newSelectedMode) + self.selectedMode = newSelectedMode + case 1: + if let firstMode = selectedMode.first { + newSelectedMode.append(contentsOf: [firstMode, searchMode]) + if let thirdMode = searchMode.children.first { + if let selectedThirdMode = selectedMode.third, searchMode.children.contains(selectedThirdMode) { + newSelectedMode.append(selectedThirdMode) + } else { + newSelectedMode.append(thirdMode) + } + } + } + self.selectedMode = newSelectedMode + case 2: + if let firstMode = selectedMode.first, let secondMode = selectedMode.second { + newSelectedMode.append(contentsOf: [firstMode, secondMode, searchMode]) + } + self.selectedMode = newSelectedMode + default: + return + } } - var third: Element? { - self.count > 2 ? self[2] : nil + private func updateSelectedMode(_ searchMode: SearchModeModel, searchModel: inout [SearchModeModel]) { + if let secondMode = searchMode.children.first { + if let selectedSecondMode = selectedMode.second, searchMode.children.contains(selectedSecondMode) { + searchModel.append(contentsOf: selectedMode.dropFirst()) + } else { + searchModel.append(secondMode) + if let thirdMode = secondMode.children.first, let selectedThirdMode = selectedMode.third { + if secondMode.children.contains(selectedThirdMode) { + searchModel.append(selectedThirdMode) + } else { + searchModel.append(thirdMode) + } + } + } + } } } diff --git a/CodeEdit/Features/WindowCommands/ViewCommands.swift b/CodeEdit/Features/WindowCommands/ViewCommands.swift index 69854c9d5..5416771ae 100644 --- a/CodeEdit/Features/WindowCommands/ViewCommands.swift +++ b/CodeEdit/Features/WindowCommands/ViewCommands.swift @@ -33,6 +33,11 @@ struct ViewCommands: Commands { } .keyboardShortcut("p", modifiers: [.shift, .command]) + Button("Open Search Navigator") { + NSApp.sendAction(#selector(CodeEditWindowController.openSearchNavigator(_:)), to: nil, from: nil) + } + .keyboardShortcut("f", modifiers: [.shift, .command]) + Menu("Font Size") { Button("Increase") { if editorFontSize < 288 { diff --git a/CodeEdit/Utils/Extensions/Array/Array+Index.swift b/CodeEdit/Utils/Extensions/Array/Array+Index.swift new file mode 100644 index 000000000..6cafca5ef --- /dev/null +++ b/CodeEdit/Utils/Extensions/Array/Array+Index.swift @@ -0,0 +1,16 @@ +// +// Array+Index.swift +// CodeEdit +// +// Created by Abe Malla on 7/24/25. +// + +extension Array { + var second: Element? { + self.count > 1 ? self[1] : nil + } + + var third: Element? { + self.count > 2 ? self[2] : nil + } +}