Skip to content

Commit fabc66e

Browse files
committed
Pre-release 0.36.124
1 parent d3cd006 commit fabc66e

File tree

14 files changed

+414
-133
lines changed

14 files changed

+414
-133
lines changed

Core/Sources/HostApp/AdvancedSettings/ChatSection.swift

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,27 @@ import Toast
55
import XcodeInspector
66

77
struct ChatSection: View {
8+
@AppStorage(\.autoAttachChatToXcode) var autoAttachChatToXcode
9+
810
var body: some View {
911
SettingsSection(title: "Chat Settings") {
10-
VStack(spacing: 10) {
11-
// Response language picker
12-
ResponseLanguageSetting()
13-
.padding(.horizontal, 10)
14-
15-
Divider()
16-
17-
// Custom instructions
18-
CustomInstructionSetting()
19-
.padding(.horizontal, 10)
20-
}
21-
.padding(.vertical, 10)
12+
// Auto Attach toggle
13+
SettingsToggle(
14+
title: "Auto-attach Chat Window to Xcode",
15+
isOn: $autoAttachChatToXcode
16+
)
17+
18+
Divider()
19+
20+
// Response language picker
21+
ResponseLanguageSetting()
22+
.padding(SettingsToggle.defaultPadding)
23+
24+
Divider()
25+
26+
// Custom instructions
27+
CustomInstructionSetting()
28+
.padding(SettingsToggle.defaultPadding)
2229
}
2330
}
2431
}

Core/Sources/HostApp/SharedComponents/SettingsToggle.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import SwiftUI
22

33
struct SettingsToggle: View {
4+
static let defaultPadding: CGFloat = 10
5+
46
let title: String
57
let isOn: Binding<Bool>
68

@@ -11,7 +13,7 @@ struct SettingsToggle: View {
1113
Toggle(isOn: isOn) {}
1214
.toggleStyle(.switch)
1315
}
14-
.padding(10)
16+
.padding(SettingsToggle.defaultPadding)
1517
}
1618
}
1719

Core/Sources/SuggestionWidget/ChatPanelWindow.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ final class ChatPanelWindow: NSWindow {
7676
}
7777
}
7878
}
79+
80+
setInitialFrame()
81+
}
82+
83+
private func setInitialFrame() {
84+
let frame = UpdateLocationStrategy.getChatPanelFrame(isAttachedToXcodeEnabled: false)
85+
setFrame(frame, display: false, animate: true)
7986
}
8087

8188
func setFloatOnTop(_ isFloatOnTop: Bool) {

Core/Sources/SuggestionWidget/ChatWindowView.swift

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ struct ChatLoadingView: View {
141141
struct ChatTitleBar: View {
142142
let store: StoreOf<ChatPanelFeature>
143143
@State var isHovering = false
144+
@AppStorage(\.autoAttachChatToXcode) var autoAttachChatToXcode
144145

145146
var body: some View {
146147
WithPerceptionTracking {
@@ -167,18 +168,20 @@ struct ChatTitleBar: View {
167168

168169
Spacer()
169170

170-
TrafficLightButton(
171-
isHovering: isHovering,
172-
isActive: store.isDetached,
173-
color: Color(nsColor: .systemCyan),
174-
action: {
175-
store.send(.toggleChatPanelDetachedButtonClicked)
171+
if !autoAttachChatToXcode {
172+
TrafficLightButton(
173+
isHovering: isHovering,
174+
isActive: store.isDetached,
175+
color: Color(nsColor: .systemCyan),
176+
action: {
177+
store.send(.toggleChatPanelDetachedButtonClicked)
178+
}
179+
) {
180+
Image(systemName: "pin.fill")
181+
.foregroundStyle(.black.opacity(0.5))
182+
.font(Font.system(size: 6).weight(.black))
183+
.transformEffect(.init(translationX: 0, y: 0.5))
176184
}
177-
) {
178-
Image(systemName: "pin.fill")
179-
.foregroundStyle(.black.opacity(0.5))
180-
.font(Font.system(size: 6).weight(.black))
181-
.transformEffect(.init(translationX: 0, y: 0.5))
182185
}
183186
}
184187
.buttonStyle(.plain)

Core/Sources/SuggestionWidget/Styles.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import SwiftUI
66
enum Style {
77
static let panelHeight: Double = 560
88
static let panelWidth: Double = 504
9+
static let minChatPanelWidth: Double = 242 // Following the minimal width of Navigator in Xcode
910
static let inlineSuggestionMaxHeight: Double = 400
1011
static let inlineSuggestionPadding: Double = 25
1112
static let widgetHeight: Double = 20

Core/Sources/SuggestionWidget/WidgetPositionStrategy.swift

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import AppKit
22
import Foundation
3+
import XcodeInspector
34

45
public struct WidgetLocation: Equatable {
56
struct PanelLocation: Equatable {
@@ -319,14 +320,41 @@ enum UpdateLocationStrategy {
319320
return selectionFrame
320321
}
321322

322-
static func getChatPanelFrame(_ screen: NSScreen) -> CGRect {
323+
static func getChatPanelFrame(isAttachedToXcodeEnabled: Bool = false) -> CGRect {
324+
let screen = NSScreen.main ?? NSScreen.screens.first!
325+
return getChatPanelFrame(screen, isAttachedToXcodeEnabled: isAttachedToXcodeEnabled)
326+
}
327+
328+
static func getChatPanelFrame(_ screen: NSScreen, isAttachedToXcodeEnabled: Bool = false) -> CGRect {
323329
let visibleScreenFrame = screen.visibleFrame
324-
// avoid too wide
325-
let width = min(Style.panelWidth, visibleScreenFrame.width * 0.3)
326-
let height = visibleScreenFrame.height
327-
let x = visibleScreenFrame.width - width
328-
329-
return CGRect(x: x, y: visibleScreenFrame.height, width: width, height: height)
330+
331+
// Default Frame
332+
var width = min(Style.panelWidth, visibleScreenFrame.width * 0.3)
333+
var height = visibleScreenFrame.height
334+
var x = visibleScreenFrame.maxX - width
335+
var y = visibleScreenFrame.minY
336+
337+
if isAttachedToXcodeEnabled,
338+
let latestActiveXcode = XcodeInspector.shared.latestActiveXcode,
339+
let xcodeWindow = latestActiveXcode.appElement.focusedWindow,
340+
let xcodeScreen = latestActiveXcode.appScreen,
341+
let xcodeRect = xcodeWindow.rect,
342+
let mainDisplayScreen = NSScreen.screens.first(where: { $0.frame.origin == .zero }) // The main display should exist
343+
{
344+
let minWidth = Style.minChatPanelWidth
345+
let visibleXcodeScreenFrame = xcodeScreen.visibleFrame
346+
347+
width = max(visibleXcodeScreenFrame.maxX - xcodeRect.maxX, minWidth)
348+
height = xcodeRect.height
349+
x = visibleXcodeScreenFrame.maxX - width
350+
351+
// AXUIElement coordinates: Y=0 at top-left
352+
// NSWindow coordinates: Y=0 at bottom-left
353+
y = mainDisplayScreen.frame.maxY - xcodeRect.maxY + mainDisplayScreen.frame.minY
354+
}
355+
356+
357+
return CGRect(x: x, y: y, width: width, height: height)
330358
}
331359
}
332360

Core/Sources/SuggestionWidget/WidgetWindowsController.swift

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,14 @@ private extension WidgetWindowsController {
142142
await updateWidgetsAndNotifyChangeOfEditor(immediately: false)
143143
case .mainWindowChanged:
144144
await updateWidgetsAndNotifyChangeOfEditor(immediately: false)
145-
case .moved,
146-
.resized,
147-
.windowMoved,
148-
.windowResized,
149-
.windowMiniaturized,
150-
.windowDeminiaturized:
145+
case .windowMiniaturized, .windowDeminiaturized:
151146
await updateWidgets(immediately: false)
147+
case .resized,
148+
.moved,
149+
.windowMoved,
150+
.windowResized:
151+
await updateWidgets(immediately: false)
152+
await updateChatWindowLocation()
152153
case .created, .uiElementDestroyed, .xcodeCompletionPanelChanged,
153154
.applicationDeactivated:
154155
continue
@@ -339,8 +340,7 @@ extension WidgetWindowsController {
339340

340341
// Generate a default location when no workspace is opened
341342
private func generateDefaultLocation() -> WidgetLocation {
342-
let mainScreen = NSScreen.main ?? NSScreen.screens.first!
343-
let chatPanelFrame = UpdateLocationStrategy.getChatPanelFrame(mainScreen)
343+
let chatPanelFrame = UpdateLocationStrategy.getChatPanelFrame(isAttachedToXcodeEnabled: false)
344344

345345
return WidgetLocation(
346346
widgetFrame: .zero,
@@ -444,6 +444,18 @@ extension WidgetWindowsController {
444444

445445
updateWindowOpacityTask = task
446446
}
447+
448+
@MainActor
449+
func updateChatWindowLocation() {
450+
let state = store.withState { $0 }
451+
let isAttachedToXcodeEnabled = UserDefaults.shared.value(for: \.autoAttachChatToXcode)
452+
if isAttachedToXcodeEnabled {
453+
if state.chatPanelState.isPanelDisplayed && !windows.chatPanelWindow.isWindowHidden {
454+
let frame = UpdateLocationStrategy.getChatPanelFrame(isAttachedToXcodeEnabled: isAttachedToXcodeEnabled)
455+
windows.chatPanelWindow.setFrame(frame, display: true, animate: true)
456+
}
457+
}
458+
}
447459

448460
func updateWindowLocation(
449461
animated: Bool,
@@ -481,8 +493,11 @@ extension WidgetWindowsController {
481493
animate: animated
482494
)
483495
}
484-
485-
if isChatPanelDetached {
496+
497+
let isAttachedToXcodeEnabled = UserDefaults.shared.value(for: \.autoAttachChatToXcode)
498+
if isAttachedToXcodeEnabled {
499+
// update in `updateChatWindowLocation`
500+
} else if isChatPanelDetached {
486501
// don't update it!
487502
} else {
488503
windows.chatPanelWindow.setFrame(
@@ -523,10 +538,10 @@ extension WidgetWindowsController {
523538

524539
@MainActor
525540
func adjustChatPanelWindowLevel() async {
541+
let window = windows.chatPanelWindow
542+
526543
let disableFloatOnTopWhenTheChatPanelIsDetached = UserDefaults.shared
527544
.value(for: \.disableFloatOnTopWhenTheChatPanelIsDetached)
528-
529-
let window = windows.chatPanelWindow
530545
guard disableFloatOnTopWhenTheChatPanelIsDetached else {
531546
window.setFloatOnTop(true)
532547
return
@@ -549,7 +564,7 @@ extension WidgetWindowsController {
549564
} else {
550565
false
551566
}
552-
567+
553568
if !floatOnTopWhenOverlapsXcode || !latestAppIsXcodeOrExtension {
554569
window.setFloatOnTop(false)
555570
} else {

Server/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"build": "webpack"
88
},
99
"dependencies": {
10-
"@github/copilot-language-server": "^1.334.0",
10+
"@github/copilot-language-server": "^1.335.0",
1111
"@xterm/addon-fit": "^0.10.0",
1212
"@xterm/xterm": "^5.5.0",
1313
"monaco-editor": "0.52.2"

Tool/Sources/Preferences/Keys.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,10 @@ public extension UserDefaultPreferenceKeys {
303303
var globalCopilotInstructions: PreferenceKey<String> {
304304
.init(defaultValue: "", key: "GlobalCopilotInstructions")
305305
}
306+
307+
var autoAttachChatToXcode: PreferenceKey<Bool> {
308+
.init(defaultValue: true, key: "AutoAttachChatToXcode")
309+
}
306310
}
307311

308312
// MARK: - Theme

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy