Skip to content

Commit e77fd16

Browse files
committed
Allow making hotkey non-global
1 parent 8dbb5eb commit e77fd16

5 files changed

Lines changed: 64 additions & 7 deletions

File tree

Core/Sources/ChatGPTChatTab/ChatPanel.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ struct ChatPanelMessages: View {
133133
.foregroundStyle(.secondary)
134134
.padding(4)
135135
}
136+
.keyboardShortcut(.downArrow, modifiers: [.command])
136137
.opacity(pinnedToBottom ? 0 : 1)
137138
.buttonStyle(.plain)
138139
.onChange(of: viewStore.state) { _ in

Core/Sources/HostApp/GeneralView.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ struct GeneralSettingsView: View {
225225
var preferWidgetToStayInsideEditorWhenWidthGreaterThan
226226
@AppStorage(\.hideCircularWidget)
227227
var hideCircularWidget
228+
@AppStorage(\.showHideWidgetShortcutGlobally)
229+
var showHideWidgetShortcutGlobally
228230
}
229231

230232
@StateObject var settings = Settings()
@@ -287,7 +289,11 @@ struct GeneralSettingsView: View {
287289
Text("pt")
288290
}
289291

290-
KeyboardShortcuts.Recorder("Global Shortcut to Toggle Widgets", name: .showHideWidget)
292+
KeyboardShortcuts.Recorder("Hotkey to Toggle Widgets", name: .showHideWidget)
293+
294+
Toggle(isOn: $settings.showHideWidgetShortcutGlobally) {
295+
Text("Enable the Hotkey Globally")
296+
}
291297

292298
Toggle(isOn: $settings.hideCircularWidget) {
293299
Text("Hide circular widget")

Core/Sources/Service/Service.swift

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import Combine
12
import Dependencies
23
import Foundation
34
import KeyboardShortcuts
45
import Workspace
56
import WorkspaceSuggestionService
7+
import XcodeInspector
68

79
#if canImport(ProService)
810
import ProService
@@ -27,6 +29,7 @@ public final class Service {
2729
public let guiController = GraphicalUserInterfaceController()
2830
public let realtimeSuggestionController = RealtimeSuggestionController()
2931
public let scheduledCleaner: ScheduledCleaner
32+
let globalShortcutManager: GlobalShortcutManager
3033

3134
#if canImport(ProService)
3235
let proService: ProService
@@ -38,6 +41,7 @@ public final class Service {
3841
scheduledCleaner = .init(workspacePool: workspacePool, guiController: guiController)
3942
workspacePool.registerPlugin { SuggestionServiceWorkspacePlugin(workspace: $0) }
4043
self.workspacePool = workspacePool
44+
globalShortcutManager = .init(guiController: guiController)
4145

4246
#if canImport(ProService)
4347
proService = withDependencies { dependencyValues in
@@ -48,8 +52,6 @@ public final class Service {
4852
ProService()
4953
}
5054
#endif
51-
52-
KeyboardShortcuts.userDefaults = .shared
5355
}
5456

5557
@MainActor
@@ -61,10 +63,51 @@ public final class Service {
6163
proService.start()
6264
#endif
6365
DependencyUpdater().update()
64-
66+
globalShortcutManager.start()
67+
}
68+
}
69+
70+
@MainActor
71+
final class GlobalShortcutManager {
72+
let guiController: GraphicalUserInterfaceController
73+
private var cancellable = Set<AnyCancellable>()
74+
75+
nonisolated init(guiController: GraphicalUserInterfaceController) {
76+
self.guiController = guiController
77+
}
78+
79+
func start() {
80+
KeyboardShortcuts.userDefaults = .shared
81+
setupShortcutIfNeeded()
82+
6583
KeyboardShortcuts.onKeyUp(for: .showHideWidget) { [guiController] in
6684
guiController.viewStore.send(.suggestionWidget(.circularWidget(.widgetClicked)))
6785
}
86+
87+
XcodeInspector.shared.$activeApplication.sink { app in
88+
if !UserDefaults.shared.value(for: \.showHideWidgetShortcutGlobally) {
89+
let shouldBeEnabled = if let app, app.isXcode || app.isExtensionService {
90+
true
91+
} else {
92+
false
93+
}
94+
if shouldBeEnabled {
95+
self.setupShortcutIfNeeded()
96+
} else {
97+
self.removeShortcutIfNeeded()
98+
}
99+
} else {
100+
self.setupShortcutIfNeeded()
101+
}
102+
}.store(in: &cancellable)
103+
}
104+
105+
func setupShortcutIfNeeded() {
106+
KeyboardShortcuts.enable(.showHideWidget)
107+
}
108+
109+
func removeShortcutIfNeeded() {
110+
KeyboardShortcuts.disable(.showHideWidget)
68111
}
69112
}
70113

Tool/Sources/Preferences/Keys.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ public struct UserDefaultPreferenceKeys {
8888
defaultValue: false,
8989
key: "HideCircularWidget"
9090
)
91+
92+
public let showHideWidgetShortcutGlobally = PreferenceKey(
93+
defaultValue: false,
94+
key: "ShowHideWidgetShortcutGlobally"
95+
)
9196
}
9297

9398
// MARK: - OpenAI Account Settings

Tool/Sources/XcodeInspector/XcodeInspector.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ public final class XcodeInspector: ObservableObject {
2424
@Published public internal(set) var focusedEditor: SourceEditor?
2525
@Published public internal(set) var focusedElement: AXUIElement?
2626
@Published public internal(set) var completionPanel: AXUIElement?
27-
27+
2828
public var focusedEditorContent: EditorInformation? {
2929
guard let documentURL = XcodeInspector.shared.realtimeActiveDocumentURL,
3030
let workspaceURL = XcodeInspector.shared.realtimeActiveWorkspaceURL,
3131
let projectURL = XcodeInspector.shared.activeProjectRootURL
3232
else { return nil }
33-
33+
3434
let editorContent = XcodeInspector.shared.focusedEditor?.content
3535
let language = languageIdentifierFromFileURL(documentURL)
3636
let relativePath = documentURL.path.replacingOccurrences(of: projectURL.path, with: "")
@@ -143,8 +143,8 @@ public final class XcodeInspector: ObservableObject {
143143

144144
@MainActor
145145
func setActiveXcode(_ xcode: XcodeAppInstanceInspector) {
146+
activeApplication = xcode
146147
xcode.refresh()
147-
148148
for task in activeXcodeObservations { task.cancel() }
149149
for cancellable in activeXcodeCancellable { cancellable.cancel() }
150150
activeXcodeObservations.removeAll()
@@ -214,6 +214,8 @@ public class AppInstanceInspector: ObservableObject {
214214
public let appElement: AXUIElement
215215
public let runningApplication: NSRunningApplication
216216
public var isActive: Bool { runningApplication.isActive }
217+
public var isXcode: Bool { runningApplication.isXcode }
218+
public var isExtensionService: Bool { runningApplication.isCopilotForXcodeExtensionService }
217219

218220
init(runningApplication: NSRunningApplication) {
219221
self.runningApplication = runningApplication

0 commit comments

Comments
 (0)