Skip to content

Commit 098d536

Browse files
committed
Merge branch 'feature/0.15.0-prerelease-bugfix' into develop
2 parents 732e438 + d99c452 commit 098d536

7 files changed

Lines changed: 110 additions & 39 deletions

File tree

Core/Sources/AXExtension/AXUIElement.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public extension AXUIElement {
1515
var title: String {
1616
(try? copyValue(key: kAXTitleAttribute)) ?? ""
1717
}
18-
18+
1919
var role: String {
2020
(try? copyValue(key: kAXRoleAttribute)) ?? ""
2121
}
@@ -32,12 +32,12 @@ public extension AXUIElement {
3232
var description: String {
3333
(try? copyValue(key: kAXDescriptionAttribute)) ?? ""
3434
}
35-
35+
3636
/// Type in Accessibility Inspector.
3737
var roleDescription: String {
3838
(try? copyValue(key: kAXRoleDescriptionAttribute)) ?? ""
3939
}
40-
40+
4141
var label: String {
4242
(try? copyValue(key: kAXLabelValueAttribute)) ?? ""
4343
}
@@ -113,6 +113,10 @@ public extension AXUIElement {
113113
(try? copyValue(key: kAXWindowsAttribute)) ?? []
114114
}
115115

116+
var isFullScreen: Bool {
117+
(try? copyValue(key: "AXFullScreen")) ?? false
118+
}
119+
116120
var focusedWindow: AXUIElement? {
117121
try? copyValue(key: kAXFocusedWindowAttribute)
118122
}
@@ -164,7 +168,7 @@ public extension AXUIElement {
164168
}
165169
return nil
166170
}
167-
171+
168172
func children(where match: (AXUIElement) -> Bool) -> [AXUIElement] {
169173
var all = [AXUIElement]()
170174
for child in children {
@@ -175,7 +179,7 @@ public extension AXUIElement {
175179
}
176180
return all
177181
}
178-
182+
179183
func firstChild(where match: (AXUIElement) -> Bool) -> AXUIElement? {
180184
for child in children {
181185
if match(child) { return child }
@@ -233,3 +237,4 @@ public extension AXUIElement {
233237
}
234238

235239
extension AXError: Error {}
240+

Core/Sources/HostApp/AccountSettings/CopilotView.swift

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import SwiftUI
77

88
struct CopilotView: View {
99
static var copilotAuthService: GitHubCopilotAuthServiceType?
10-
10+
1111
class Settings: ObservableObject {
1212
@AppStorage(\.nodePath) var nodePath: String
1313
@AppStorage(\.runNodeWith) var runNodeWith
@@ -26,7 +26,7 @@ struct CopilotView: View {
2626
@State var version: String?
2727
@State var isRunningAction: Bool = false
2828
@State var isUserCodeCopiedAlertPresented = false
29-
29+
3030
func getGitHubCopilotAuthService() throws -> GitHubCopilotAuthServiceType {
3131
if let service = Self.copilotAuthService { return service }
3232
let service = try GitHubCopilotAuthService()
@@ -56,17 +56,15 @@ struct CopilotView: View {
5656
} label: {
5757
Text("Run Node with")
5858
}
59-
60-
VStack { // workaround a layout issue of SwiftUI
61-
Text(
62-
"You may have to restart the helper app to apply the changes. To do so, simply close the helper app by clicking on the menu bar icon that looks like a steer wheel, it will automatically restart as needed."
63-
)
64-
.lineLimit(nil)
65-
.fixedSize(horizontal: false, vertical: true)
66-
.foregroundColor(.secondary)
67-
}
6859
}
6960

61+
Text(
62+
"You may have to restart the helper app to apply the changes. To do so, simply close the helper app by clicking on the menu bar icon that looks like a steer wheel, it will automatically restart as needed."
63+
)
64+
.lineLimit(6)
65+
.fixedSize(horizontal: false, vertical: true)
66+
.foregroundColor(.secondary)
67+
7068
VStack(alignment: .leading) {
7169
Text("Language Server Version: \(version ?? "Loading..")")
7270
Text("Status: \(status?.description ?? "Loading..")")
@@ -104,9 +102,9 @@ struct CopilotView: View {
104102
RoundedRectangle(cornerRadius: 8)
105103
.stroke(Color(nsColor: .separatorColor), style: .init(lineWidth: 1))
106104
}
107-
105+
108106
Divider()
109-
107+
110108
Form {
111109
Toggle("Verbose Log", isOn: $settings.gitHubCopilotVerboseLog)
112110
}
@@ -128,7 +126,7 @@ struct CopilotView: View {
128126
version = try await service.version()
129127
isRunningAction = false
130128

131-
if status != .ok && status != .notSignedIn {
129+
if status != .ok, status != .notSignedIn {
132130
toast(
133131
Text(
134132
"GitHub Copilot status is not \"ok\". Please check if you have a valid GitHub Copilot subscription."

Core/Sources/Service/GUI/PromptToCodeProvider+Service.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import ActiveApplicationMonitor
12
import Combine
23
import PromptToCodeService
34
import SuggestionWidget
@@ -58,6 +59,9 @@ extension PromptToCodeProvider {
5859
Task { @ServiceActor in
5960
let handler = PseudoCommandHandler()
6061
await handler.acceptSuggestion()
62+
if let app = ActiveApplicationMonitor.previousActiveApplication, app.isXcode {
63+
app.activate()
64+
}
6165
}
6266
}
6367

@@ -74,3 +78,4 @@ extension PromptToCodeProvider {
7478
}
7579
}
7680
}
81+

Core/Sources/Service/GUI/WidgetDataSource.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,22 @@ extension WidgetDataSource: SuggestionWidgetDataSource {
173173
Task { @ServiceActor in
174174
let handler = PseudoCommandHandler()
175175
await handler.rejectSuggestions()
176+
if let app = ActiveApplicationMonitor.previousActiveApplication,
177+
app.isXcode
178+
{
179+
app.activate()
180+
}
176181
}
177182
},
178183
onAcceptSuggestionTapped: {
179184
Task { @ServiceActor in
180185
let handler = PseudoCommandHandler()
181186
await handler.acceptSuggestion()
187+
if let app = ActiveApplicationMonitor.previousActiveApplication,
188+
app.isXcode
189+
{
190+
app.activate()
191+
}
182192
}
183193
}
184194
)

Core/Sources/SuggestionWidget/ChatWindowView.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import ActiveApplicationMonitor
12
import AppKit
23
import SwiftUI
34

@@ -9,7 +10,7 @@ final class ChatWindowViewModel: ObservableObject {
910
@Published var colorScheme: ColorScheme
1011
@Published var isPanelDisplayed = false
1112
@Published var chatPanelInASeparateWindow = false
12-
13+
1314
public init(chat: ChatProvider? = nil, colorScheme: ColorScheme = .dark) {
1415
self.chat = chat
1516
self.colorScheme = colorScheme
@@ -26,6 +27,11 @@ struct ChatWindowView: View {
2627
.background {
2728
Button(action: {
2829
viewModel.isPanelDisplayed = false
30+
if let app = ActiveApplicationMonitor.previousActiveApplication,
31+
app.isXcode
32+
{
33+
app.activate()
34+
}
2935
}) {
3036
EmptyView()
3137
}
@@ -38,3 +44,4 @@ struct ChatWindowView: View {
3844
.preferredColorScheme(viewModel.colorScheme)
3945
}
4046
}
47+

Core/Sources/SuggestionWidget/SuggestionWidgetController.swift

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@ import UserDefaultsObserver
1010

1111
@MainActor
1212
public final class SuggestionWidgetController: NSObject {
13+
private lazy var fullscreenDetector = {
14+
let it = CanBecomeKeyWindow(
15+
contentRect: .zero,
16+
styleMask: .borderless,
17+
backing: .buffered,
18+
defer: false
19+
)
20+
it.isReleasedWhenClosed = false
21+
it.isOpaque = false
22+
it.backgroundColor = .clear
23+
it.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
24+
it.hasShadow = false
25+
it.setIsVisible(true)
26+
it.canBecomeKeyChecker = { false }
27+
return it
28+
}()
29+
1330
private lazy var widgetWindow = {
1431
let it = CanBecomeKeyWindow(
1532
contentRect: .zero,
@@ -21,7 +38,7 @@ public final class SuggestionWidgetController: NSObject {
2138
it.isOpaque = false
2239
it.backgroundColor = .clear
2340
it.level = .init(19)
24-
it.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
41+
it.collectionBehavior = [.fullScreenAuxiliary]
2542
it.hasShadow = true
2643
it.contentView = NSHostingView(
2744
rootView: WidgetView(
@@ -52,7 +69,7 @@ public final class SuggestionWidgetController: NSObject {
5269
it.isOpaque = false
5370
it.backgroundColor = .clear
5471
it.level = .init(19)
55-
it.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
72+
it.collectionBehavior = [.fullScreenAuxiliary]
5673
it.hasShadow = true
5774
it.contentView = NSHostingView(
5875
rootView: TabView(chatWindowViewModel: chatWindowViewModel)
@@ -64,7 +81,7 @@ public final class SuggestionWidgetController: NSObject {
6481

6582
private lazy var panelWindow = {
6683
let it = CanBecomeKeyWindow(
67-
contentRect: .zero,
84+
contentRect: .init(x: 0, y: 0, width: Style.panelWidth, height: Style.panelHeight),
6885
styleMask: .borderless,
6986
backing: .buffered,
7087
defer: false
@@ -73,16 +90,13 @@ public final class SuggestionWidgetController: NSObject {
7390
it.isOpaque = false
7491
it.backgroundColor = .clear
7592
it.level = .init(NSWindow.Level.floating.rawValue + 1)
76-
it.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
93+
it.collectionBehavior = [.fullScreenAuxiliary]
7794
it.hasShadow = true
7895
it.contentView = NSHostingView(
7996
rootView: SuggestionPanelView(viewModel: suggestionPanelViewModel)
8097
)
8198
it.setIsVisible(true)
82-
it.canBecomeKeyChecker = { [suggestionPanelViewModel] in
83-
if case .promptToCode = suggestionPanelViewModel.content { return true }
84-
return false
85-
}
99+
it.canBecomeKeyChecker = { true }
86100
return it
87101
}()
88102

@@ -97,7 +111,7 @@ public final class SuggestionWidgetController: NSObject {
97111
it.isOpaque = false
98112
it.backgroundColor = .clear
99113
it.level = .floating
100-
it.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
114+
it.collectionBehavior = [.fullScreenAuxiliary]
101115
it.hasShadow = true
102116
it.contentView = NSHostingView(
103117
rootView: ChatWindowView(viewModel: chatWindowViewModel)
@@ -128,6 +142,7 @@ public final class SuggestionWidgetController: NSObject {
128142
private var windowChangeObservationTask: Task<Void, Error>?
129143
private var activeApplicationMonitorTask: Task<Void, Error>?
130144
private var sourceEditorMonitorTask: Task<Void, Error>?
145+
private var fullscreenDetectingTask: Task<Void, Error>?
131146
private var currentFileURL: URL?
132147
private var colorScheme: ColorScheme = .light
133148
private var cancellable = Set<AnyCancellable>()
@@ -174,6 +189,27 @@ public final class SuggestionWidgetController: NSObject {
174189
}
175190
}
176191

192+
Task { @MainActor in
193+
fullscreenDetectingTask = Task { [weak self] in
194+
let sequence = NSWorkspace.shared.notificationCenter
195+
.notifications(named: NSWorkspace.activeSpaceDidChangeNotification)
196+
_ = self?.fullscreenDetector
197+
for await _ in sequence {
198+
try Task.checkCancellation()
199+
guard let self else { return }
200+
guard let activeXcode = ActiveApplicationMonitor.activeXcode else { continue }
201+
guard fullscreenDetector.isOnActiveSpace else { continue }
202+
let app = AXUIElementCreateApplication(activeXcode.processIdentifier)
203+
if let window = app.focusedWindow, window.isFullScreen {
204+
widgetWindow.orderFrontRegardless()
205+
tabWindow.orderFrontRegardless()
206+
panelWindow.orderFrontRegardless()
207+
chatWindow.orderFrontRegardless()
208+
}
209+
}
210+
}
211+
}
212+
177213
Task { @MainActor in
178214
presentationModeChangeObserver.onChange = { [weak self] in
179215
guard let self else { return }
@@ -224,7 +260,7 @@ public final class SuggestionWidgetController: NSObject {
224260
}
225261
}
226262
}
227-
263+
228264
public func detachChat() {
229265
chatWindowViewModel.chatPanelInASeparateWindow = true
230266
}
@@ -499,16 +535,14 @@ extension SuggestionWidgetController {
499535
}
500536

501537
if let app = ActiveApplicationMonitor.activeApplication, app.isXcode {
502-
let application = AXUIElementCreateApplication(app.processIdentifier)
503-
let noFocus = application.focusedWindow == nil
504-
panelWindow.alphaValue = noFocus ? 0 : 1
505-
widgetWindow.alphaValue = noFocus ? 0 : 1
506-
tabWindow.alphaValue = noFocus ? 0 : 1
538+
panelWindow.alphaValue = 1
539+
widgetWindow.alphaValue = 1
540+
tabWindow.alphaValue = 1
507541

508542
if detachChat {
509543
chatWindow.alphaValue = chatWindowViewModel.chat != nil ? 1 : 0
510544
} else {
511-
chatWindow.alphaValue = noFocus ? 0 : 1
545+
chatWindow.alphaValue = 1
512546
}
513547
} else if let app = ActiveApplicationMonitor.activeApplication,
514548
app.bundleIdentifier == Bundle.main.bundleIdentifier
@@ -584,6 +618,7 @@ extension SuggestionWidgetController: NSWindowDelegate {
584618
var mouseLocation = NSEvent.mouseLocation
585619
let windowFrame = chatWindow.frame
586620
if mouseLocation.y > windowFrame.maxY - 40,
621+
mouseLocation.y < windowFrame.maxY,
587622
mouseLocation.x > windowFrame.minX,
588623
mouseLocation.x < windowFrame.maxX
589624
{
@@ -616,6 +651,7 @@ class ChatWindow: NSWindow {
616651
let windowFrame = frame
617652
let currentLocation = event.locationInWindow
618653
if currentLocation.y > windowFrame.size.height - 40,
654+
currentLocation.y < windowFrame.size.height,
619655
currentLocation.x > 0,
620656
currentLocation.x < windowFrame.width
621657
{

Core/Sources/SuggestionWidget/WidgetView.swift

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import ActiveApplicationMonitor
12
import Environment
23
import Preferences
34
import SuggestionModel
@@ -26,15 +27,24 @@ struct WidgetView: View {
2627
Circle().fill(isHovering ? .white.opacity(0.8) : .white.opacity(0.3))
2728
.onTapGesture {
2829
withAnimation(.easeInOut(duration: 0.2)) {
29-
let isDisplayed = {
30+
let wasDisplayed = {
3031
if panelViewModel.isPanelDisplayed,
3132
panelViewModel.content != nil { return true }
3233
if chatWindowViewModel.isPanelDisplayed,
3334
chatWindowViewModel.chat != nil { return true }
3435
return false
3536
}()
36-
panelViewModel.isPanelDisplayed = !isDisplayed
37-
chatWindowViewModel.isPanelDisplayed = !isDisplayed
37+
panelViewModel.isPanelDisplayed = !wasDisplayed
38+
chatWindowViewModel.isPanelDisplayed = !wasDisplayed
39+
let isDisplayed = !wasDisplayed
40+
41+
if !isDisplayed {
42+
if let app = ActiveApplicationMonitor.previousActiveApplication,
43+
app.isXcode
44+
{
45+
app.activate()
46+
}
47+
}
3848
}
3949
}
4050
.overlay {

0 commit comments

Comments
 (0)