From 432c72e23f76670db29ebb2ef212a194ce108e9d Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 00:56:18 +0800 Subject: [PATCH 01/22] Remove the snapshot check when getting suggestions manually --- .../WindowBaseCommandHandler.swift | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Core/Sources/Service/SuggestionCommandHandler/WindowBaseCommandHandler.swift b/Core/Sources/Service/SuggestionCommandHandler/WindowBaseCommandHandler.swift index 2bf83cfe..d4f0d52e 100644 --- a/Core/Sources/Service/SuggestionCommandHandler/WindowBaseCommandHandler.swift +++ b/Core/Sources/Service/SuggestionCommandHandler/WindowBaseCommandHandler.swift @@ -46,14 +46,6 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler { try Task.checkCancellation() - let snapshot = FilespaceSuggestionSnapshot( - linesHash: editor.lines.hashValue, - cursorPosition: editor.cursorPosition - ) - - // There is no need to regenerate suggestions for the same editor content. - guard filespace.suggestionSourceSnapshot != snapshot else { return } - try await workspace.generateSuggestions( forFileAt: fileURL, editor: editor From e27b1ab588234089c78ca1a990df5cc57079cef1 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 01:51:40 +0800 Subject: [PATCH 02/22] Prevent sending discard suggestion action when there is no suggestion displayed --- .../SuggestionWidget/SuggestionWidgetController.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Core/Sources/SuggestionWidget/SuggestionWidgetController.swift b/Core/Sources/SuggestionWidget/SuggestionWidgetController.swift index 0c1cc709..87cbf182 100644 --- a/Core/Sources/SuggestionWidget/SuggestionWidgetController.swift +++ b/Core/Sources/SuggestionWidget/SuggestionWidgetController.swift @@ -51,7 +51,11 @@ public extension SuggestionWidgetController { } func discardSuggestion() { - store.send(.panel(.discardSuggestion)) + store.withState { state in + if state.panelState.content.suggestion != nil { + store.send(.panel(.discardSuggestion)) + } + } } #warning("TODO: Make a progress controller that doesn't use TCA.") From ec69b1206491353e4ce9379139ba8f1181be0598 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 01:52:42 +0800 Subject: [PATCH 03/22] Rename methods --- .../SuggestionWidget/WidgetWindowsController.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/Sources/SuggestionWidget/WidgetWindowsController.swift b/Core/Sources/SuggestionWidget/WidgetWindowsController.swift index 454c79ee..a6fd1818 100644 --- a/Core/Sources/SuggestionWidget/WidgetWindowsController.swift +++ b/Core/Sources/SuggestionWidget/WidgetWindowsController.swift @@ -58,7 +58,7 @@ actor WidgetWindowsController: NSObject { xcodeInspector.$focusedEditor.sink { [weak self] editor in guard let editor else { return } - Task { [weak self] in await self?.observe(to: editor) } + Task { [weak self] in await self?.observe(toEditor: editor) } }.store(in: &cancellable) xcodeInspector.$completionPanel.sink { [weak self] newValue in @@ -278,10 +278,10 @@ private extension WidgetWindowsController { } guard currentApplicationProcessIdentifier != app.processIdentifier else { return } currentApplicationProcessIdentifier = app.processIdentifier - observe(to: app) + observe(toApp: app) } - func observe(to app: AppInstanceInspector) { + func observe(toApp app: AppInstanceInspector) { guard let app = app as? XcodeAppInstanceInspector else { return } let notifications = app.axNotifications observeToAppTask?.cancel() @@ -337,7 +337,7 @@ private extension WidgetWindowsController { } } - func observe(to editor: SourceEditor) { + func observe(toEditor editor: SourceEditor) { observeToFocusedEditorTask?.cancel() observeToFocusedEditorTask = Task { let selectionRangeChange = await editor.axNotifications.notifications() From f15a7476f741820cf9574aace2c03d040fd95050 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 02:38:49 +0800 Subject: [PATCH 04/22] Remove unneeded calls --- .../SuggestionWidget/FeatureReducers/WidgetFeature.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Core/Sources/SuggestionWidget/FeatureReducers/WidgetFeature.swift b/Core/Sources/SuggestionWidget/FeatureReducers/WidgetFeature.swift index ba4a81bc..cee3d93c 100644 --- a/Core/Sources/SuggestionWidget/FeatureReducers/WidgetFeature.swift +++ b/Core/Sources/SuggestionWidget/FeatureReducers/WidgetFeature.swift @@ -295,11 +295,7 @@ public struct WidgetFeature: ReducerProtocol { }.cancellable(id: CancelID.observeUserDefaults, cancelInFlight: true) case .updateActiveApplication: - return .run { send in - if let app = await xcodeInspector.safe.activeApplication, app.isXcode { - await send(.panel(.switchToAnotherEditorAndUpdateContent)) - } - } + return .none case .updateColorScheme: let widgetColorScheme = UserDefaults.shared.value(for: \.widgetColorScheme) From 8e690b308135b21baddb61a2c337530e63408f85 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 02:40:20 +0800 Subject: [PATCH 05/22] Fix that triggering the menubar dismisses suggestions --- .../FeatureReducers/PanelFeature.swift | 2 -- .../WidgetWindowsController.swift | 16 +++++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Core/Sources/SuggestionWidget/FeatureReducers/PanelFeature.swift b/Core/Sources/SuggestionWidget/FeatureReducers/PanelFeature.swift index 48d92447..954c5743 100644 --- a/Core/Sources/SuggestionWidget/FeatureReducers/PanelFeature.swift +++ b/Core/Sources/SuggestionWidget/FeatureReducers/PanelFeature.swift @@ -95,8 +95,6 @@ public struct PanelFeature: ReducerProtocol { return .none case .switchToAnotherEditorAndUpdateContent: - state.content.error = nil - state.content.suggestion = nil return .run { send in guard let fileURL = await xcodeInspector.safe.realtimeActiveDocumentURL else { return } diff --git a/Core/Sources/SuggestionWidget/WidgetWindowsController.swift b/Core/Sources/SuggestionWidget/WidgetWindowsController.swift index a6fd1818..60ff0b18 100644 --- a/Core/Sources/SuggestionWidget/WidgetWindowsController.swift +++ b/Core/Sources/SuggestionWidget/WidgetWindowsController.swift @@ -288,7 +288,6 @@ private extension WidgetWindowsController { observeToAppTask = Task { await windows.orderFront() - let documentURL = await MainActor.run { store.withState { $0.focusingDocumentURL } } for await notification in await notifications.notifications() { try Task.checkCancellation() @@ -296,12 +295,17 @@ private extension WidgetWindowsController { /// so the transition looks better. func hideWidgetForTransitions() async { let newDocumentURL = await xcodeInspector.safe.realtimeActiveDocumentURL + let documentURL = await MainActor.run { store.withState { $0.focusingDocumentURL } } if documentURL != newDocumentURL { await send(.panel(.removeDisplayedContent)) await hidePanelWindows() } await send(.updateFocusingDocumentURL) } + + func removeContent() async { + await send(.panel(.removeDisplayedContent)) + } func updateWidgetsAndNotifyChangeOfEditor(immediately: Bool) async { await send(.panel(.switchToAnotherEditorAndUpdateContent)) @@ -309,9 +313,9 @@ private extension WidgetWindowsController { updateWindowOpacity(immediately: immediately) } - func updateWidgets() async { - updateWindowLocation(animated: false, immediately: false) - updateWindowOpacity(immediately: false) + func updateWidgets(immediately: Bool) async { + updateWindowLocation(animated: false, immediately: immediately) + updateWindowOpacity(immediately: immediately) } switch notification.kind { @@ -319,8 +323,10 @@ private extension WidgetWindowsController { await hideWidgetForTransitions() await updateWidgetsAndNotifyChangeOfEditor(immediately: true) case .applicationActivated: + await removeContent() await updateWidgetsAndNotifyChangeOfEditor(immediately: false) case .mainWindowChanged: + await removeContent() await updateWidgetsAndNotifyChangeOfEditor(immediately: false) case .moved, .resized, @@ -328,7 +334,7 @@ private extension WidgetWindowsController { .windowResized, .windowMiniaturized, .windowDeminiaturized: - await updateWidgets() + await updateWidgets(immediately: false) case .created, .uiElementDestroyed, .xcodeCompletionPanelChanged, .applicationDeactivated: continue From 48ce9989e93fab8db6bc96ad1126463322df89e3 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 03:09:09 +0800 Subject: [PATCH 06/22] Add feature flags --- Core/Sources/HostApp/DebugView.swift | 18 ++++++++++++++++++ Tool/Package.swift | 1 + Tool/Sources/Preferences/Keys.swift | 8 ++++++++ 3 files changed, 27 insertions(+) diff --git a/Core/Sources/HostApp/DebugView.swift b/Core/Sources/HostApp/DebugView.swift index 08d46bbc..ba118379 100644 --- a/Core/Sources/HostApp/DebugView.swift +++ b/Core/Sources/HostApp/DebugView.swift @@ -25,6 +25,10 @@ final class DebugSettings: ObservableObject { var restartXcodeInspectorIfAccessibilityAPIIsMalfunctioningNoTimer @AppStorage(\.toastForTheReasonWhyXcodeInspectorNeedsToBeRestarted) var toastForTheReasonWhyXcodeInspectorNeedsToBeRestarted + @AppStorage(\.observeToAXNotificationOnAnotherThread) + var observeToAXNotificationOnAnotherThread + @AppStorage(\.observeToAXNotificationWithDefaultMode) + var observeToAXNotificationWithDefaultMode init() {} } @@ -116,6 +120,20 @@ struct DebugSettingsView: View { UserDefaults.shared.set(nil, forKey: "ChatModels") UserDefaults.shared.set(nil, forKey: "EmbeddingModels") } + + Group { + Toggle( + isOn: $settings.observeToAXNotificationOnAnotherThread + ) { + Text("Observe to AXNotification on background thread") + } + + Toggle( + isOn: $settings.observeToAXNotificationWithDefaultMode + ) { + Text("Observe to AXNotification with default mode") + } + } } } .padding() diff --git a/Tool/Package.swift b/Tool/Package.swift index 49950fa8..61b90ca5 100644 --- a/Tool/Package.swift +++ b/Tool/Package.swift @@ -160,6 +160,7 @@ let package = Package( .target( name: "AXNotificationStream", dependencies: [ + "Preferences", "Logger", ] ), diff --git a/Tool/Sources/Preferences/Keys.swift b/Tool/Sources/Preferences/Keys.swift index d1257dbf..257e7bd4 100644 --- a/Tool/Sources/Preferences/Keys.swift +++ b/Tool/Sources/Preferences/Keys.swift @@ -604,5 +604,13 @@ public extension UserDefaultPreferenceKeys { key: "FeatureFlag-ToastForTheReasonWhyXcodeInspectorNeedsToBeRestarted" ) } + + var observeToAXNotificationOnAnotherThread: FeatureFlag { + .init(defaultValue: false, key: "FeatureFlag-observeToAXNotificationOnAnotherThread") + } + + var observeToAXNotificationWithDefaultMode: FeatureFlag { + .init(defaultValue: false, key: "FeatureFlag-observeToAXNotificationWithDefaultMode") + } } From f6b04ed885f3b0003d82b5a9204206187025b2f7 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 03:09:28 +0800 Subject: [PATCH 07/22] Change runloop and mode according to flags --- .../AXNotificationStream.swift | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Tool/Sources/AXNotificationStream/AXNotificationStream.swift b/Tool/Sources/AXNotificationStream/AXNotificationStream.swift index 6287944a..f80f2f0c 100644 --- a/Tool/Sources/AXNotificationStream/AXNotificationStream.swift +++ b/Tool/Sources/AXNotificationStream/AXNotificationStream.swift @@ -2,6 +2,7 @@ import AppKit import ApplicationServices import Foundation import Logger +import Preferences public final class AXNotificationStream: AsyncSequence { public typealias Stream = AsyncStream @@ -53,6 +54,15 @@ public final class AXNotificationStream: AsyncSequence { self.file = file self.line = line self.function = function + + let mode: CFRunLoopMode = UserDefaults.shared + .value(for: \.observeToAXNotificationWithDefaultMode) ? .defaultMode : .commonModes + + let runLoop: CFRunLoop = UserDefaults.shared + .value(for: \.observeToAXNotificationOnAnotherThread) + ? DispatchQueue.global(qos: .userInteractive).sync { CFRunLoopGetCurrent() } + : CFRunLoopGetMain() + var cont: Continuation! stream = Stream { continuation in cont = continuation @@ -88,17 +98,17 @@ public final class AXNotificationStream: AsyncSequence { AXObserverRemoveNotification(observer, observingElement, name as CFString) } CFRunLoopRemoveSource( - CFRunLoopGetMain(), + runLoop, AXObserverGetRunLoopSource(observer), - .commonModes + mode ) } Task { @MainActor [weak self] in CFRunLoopAddSource( - CFRunLoopGetMain(), + runLoop, AXObserverGetRunLoopSource(observer), - .commonModes + mode ) var pendingRegistrationNames = Set(notificationNames) var retry = 0 From 014023a1632c8595f7d7c5d49a6ba6a6f84d6d81 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 03:25:47 +0800 Subject: [PATCH 08/22] Update --- Pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pro b/Pro index a3792303..d291886a 160000 --- a/Pro +++ b/Pro @@ -1 +1 @@ -Subproject commit a37923038f72208000a3829683d7bdfb8d939e28 +Subproject commit d291886a85c1c73c05a38273a64c003503fba505 From 72fb69a1326aead727062c74f2db560a1a09cfa3 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 03:29:12 +0800 Subject: [PATCH 09/22] Update texts --- .../HostApp/FeatureSettings/ChatSettingsView.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/Sources/HostApp/FeatureSettings/ChatSettingsView.swift b/Core/Sources/HostApp/FeatureSettings/ChatSettingsView.swift index 633cc5ee..aaeb7af4 100644 --- a/Core/Sources/HostApp/FeatureSettings/ChatSettingsView.swift +++ b/Core/Sources/HostApp/FeatureSettings/ChatSettingsView.swift @@ -313,7 +313,7 @@ struct ChatSettingsView: View { "Preferred Chat Model", selection: $settings.preferredChatModelIdForSenseScope ) { - Text("None").tag("") + Text("Use the default model").tag("") if !settings.chatModels .contains(where: { @@ -364,7 +364,7 @@ struct ChatSettingsView: View { "Preferred Chat Model", selection: $settings.preferredChatModelIdForProjectScope ) { - Text("None").tag("") + Text("Use the default model").tag("") if !settings.chatModels .contains(where: { @@ -390,7 +390,7 @@ struct ChatSettingsView: View { SubSection( title: Text("Web Scope"), - description: "Allow the bot to search on Bing or read a web page." + description: "Allow the bot to search on Bing or read a web page. The current implementation requires function calling." ) { Form { Toggle(isOn: $settings.enableWebScopeByDefaultInChatContext) { @@ -401,7 +401,7 @@ struct ChatSettingsView: View { "Preferred Chat Model", selection: $settings.preferredChatModelIdForWebScope ) { - Text("None").tag("") + Text("Use the default model").tag("") if !settings.chatModels .contains(where: { From a7d1e74e8a9786e845f56ab8055fe773574afd4d Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 03:29:20 +0800 Subject: [PATCH 10/22] Bump version to 0.31.2 --- Version.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Version.xcconfig b/Version.xcconfig index c8e46a98..21e74a54 100644 --- a/Version.xcconfig +++ b/Version.xcconfig @@ -1,3 +1,3 @@ -APP_VERSION = 0.31.1 -APP_BUILD = 334 +APP_VERSION = 0.31.2 +APP_BUILD = 338 From 1ba39c71b8e24abf37993b6037abb5d8bc743005 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 15:07:36 +0800 Subject: [PATCH 11/22] Remove a feature flag --- Core/Sources/HostApp/DebugView.swift | 11 ++--------- .../AXNotificationStream/AXNotificationStream.swift | 5 +---- Tool/Sources/Preferences/Keys.swift | 4 ---- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/Core/Sources/HostApp/DebugView.swift b/Core/Sources/HostApp/DebugView.swift index ba118379..cba2be49 100644 --- a/Core/Sources/HostApp/DebugView.swift +++ b/Core/Sources/HostApp/DebugView.swift @@ -25,8 +25,6 @@ final class DebugSettings: ObservableObject { var restartXcodeInspectorIfAccessibilityAPIIsMalfunctioningNoTimer @AppStorage(\.toastForTheReasonWhyXcodeInspectorNeedsToBeRestarted) var toastForTheReasonWhyXcodeInspectorNeedsToBeRestarted - @AppStorage(\.observeToAXNotificationOnAnotherThread) - var observeToAXNotificationOnAnotherThread @AppStorage(\.observeToAXNotificationWithDefaultMode) var observeToAXNotificationWithDefaultMode init() {} @@ -120,14 +118,8 @@ struct DebugSettingsView: View { UserDefaults.shared.set(nil, forKey: "ChatModels") UserDefaults.shared.set(nil, forKey: "EmbeddingModels") } - - Group { - Toggle( - isOn: $settings.observeToAXNotificationOnAnotherThread - ) { - Text("Observe to AXNotification on background thread") - } + Group { Toggle( isOn: $settings.observeToAXNotificationWithDefaultMode ) { @@ -136,6 +128,7 @@ struct DebugSettingsView: View { } } } + .frame(maxWidth: .infinity) .padding() } } diff --git a/Tool/Sources/AXNotificationStream/AXNotificationStream.swift b/Tool/Sources/AXNotificationStream/AXNotificationStream.swift index f80f2f0c..89fca015 100644 --- a/Tool/Sources/AXNotificationStream/AXNotificationStream.swift +++ b/Tool/Sources/AXNotificationStream/AXNotificationStream.swift @@ -58,10 +58,7 @@ public final class AXNotificationStream: AsyncSequence { let mode: CFRunLoopMode = UserDefaults.shared .value(for: \.observeToAXNotificationWithDefaultMode) ? .defaultMode : .commonModes - let runLoop: CFRunLoop = UserDefaults.shared - .value(for: \.observeToAXNotificationOnAnotherThread) - ? DispatchQueue.global(qos: .userInteractive).sync { CFRunLoopGetCurrent() } - : CFRunLoopGetMain() + let runLoop: CFRunLoop = CFRunLoopGetMain() var cont: Continuation! stream = Stream { continuation in diff --git a/Tool/Sources/Preferences/Keys.swift b/Tool/Sources/Preferences/Keys.swift index 257e7bd4..d020accf 100644 --- a/Tool/Sources/Preferences/Keys.swift +++ b/Tool/Sources/Preferences/Keys.swift @@ -605,10 +605,6 @@ public extension UserDefaultPreferenceKeys { ) } - var observeToAXNotificationOnAnotherThread: FeatureFlag { - .init(defaultValue: false, key: "FeatureFlag-observeToAXNotificationOnAnotherThread") - } - var observeToAXNotificationWithDefaultMode: FeatureFlag { .init(defaultValue: false, key: "FeatureFlag-observeToAXNotificationWithDefaultMode") } From c56de951243a8b298b174fa7316c24edf1f92271 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 15:07:41 +0800 Subject: [PATCH 12/22] Update --- Pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pro b/Pro index d291886a..73744057 160000 --- a/Pro +++ b/Pro @@ -1 +1 @@ -Subproject commit d291886a85c1c73c05a38273a64c003503fba505 +Subproject commit 73744057e14bb107b35289022ae22efc7b46ce8c From 9f25f4991344228168cc252cf901e5a812fd9ec0 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 15:48:46 +0800 Subject: [PATCH 13/22] Update UI to look better in light mode --- Core/Sources/SuggestionWidget/Styles.swift | 20 ++++++++++++---- .../CodeBlockSuggestionPanel.swift | 24 +++---------------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/Core/Sources/SuggestionWidget/Styles.swift b/Core/Sources/SuggestionWidget/Styles.swift index 8aa87817..d90ded61 100644 --- a/Core/Sources/SuggestionWidget/Styles.swift +++ b/Core/Sources/SuggestionWidget/Styles.swift @@ -45,12 +45,16 @@ extension NSAppearance { } } -extension View { - func xcodeStyleFrame(cornerRadius: Double = 8) -> some View { - clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)) - .overlay( +struct XcodeLikeFrame: View { + @Environment(\.colorScheme) var colorScheme + let content: Content + let cornerRadius: Double + + var body: some View { + content.clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)) + .background( RoundedRectangle(cornerRadius: cornerRadius, style: .continuous) - .stroke(Color.black.opacity(0.3), style: .init(lineWidth: 1)) + .fill(Material.bar) ) .overlay( RoundedRectangle(cornerRadius: max(0, cornerRadius - 1), style: .continuous) @@ -60,6 +64,12 @@ extension View { } } +extension View { + func xcodeStyleFrame(cornerRadius: Double = 10) -> some View { + XcodeLikeFrame(content: self, cornerRadius: cornerRadius) + } +} + extension MarkdownUI.Theme { static func custom(fontSize: Double) -> MarkdownUI.Theme { .gitHub.text { diff --git a/Core/Sources/SuggestionWidget/SuggestionPanelContent/CodeBlockSuggestionPanel.swift b/Core/Sources/SuggestionWidget/SuggestionPanelContent/CodeBlockSuggestionPanel.swift index b42e37ea..59aae933 100644 --- a/Core/Sources/SuggestionWidget/SuggestionPanelContent/CodeBlockSuggestionPanel.swift +++ b/Core/Sources/SuggestionWidget/SuggestionPanelContent/CodeBlockSuggestionPanel.swift @@ -143,13 +143,7 @@ struct CodeBlockSuggestionPanel: View { }() )) .frame(width: 450, height: 400) - .background { - HStack { - Color.red - Color.green - Color.blue - } - } + .padding() } #Preview("Code Block Suggestion Panel Compact Mode") { @@ -178,13 +172,7 @@ struct CodeBlockSuggestionPanel: View { )) .preferredColorScheme(.light) .frame(width: 450, height: 400) - .background { - HStack { - Color.red - Color.green - Color.blue - } - } + .padding() } #Preview("Code Block Suggestion Panel Highlight ObjC") { @@ -201,12 +189,6 @@ struct CodeBlockSuggestionPanel: View { )) .preferredColorScheme(.light) .frame(width: 450, height: 400) - .background { - HStack { - Color.red - Color.green - Color.blue - } - } + .padding() } From bd5064ebe795dcdca4f5dade3676ac9ecbdab959 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 15:54:45 +0800 Subject: [PATCH 14/22] Update suggestion panel corner radius to match Xcode completion panel --- Core/Sources/SuggestionWidget/Styles.swift | 4 ++-- .../SuggestionPanelContent/CodeBlockSuggestionPanel.swift | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Core/Sources/SuggestionWidget/Styles.swift b/Core/Sources/SuggestionWidget/Styles.swift index d90ded61..393591ea 100644 --- a/Core/Sources/SuggestionWidget/Styles.swift +++ b/Core/Sources/SuggestionWidget/Styles.swift @@ -65,8 +65,8 @@ struct XcodeLikeFrame: View { } extension View { - func xcodeStyleFrame(cornerRadius: Double = 10) -> some View { - XcodeLikeFrame(content: self, cornerRadius: cornerRadius) + func xcodeStyleFrame(cornerRadius: Double? = nil) -> some View { + XcodeLikeFrame(content: self, cornerRadius: cornerRadius ?? 10) } } diff --git a/Core/Sources/SuggestionWidget/SuggestionPanelContent/CodeBlockSuggestionPanel.swift b/Core/Sources/SuggestionWidget/SuggestionPanelContent/CodeBlockSuggestionPanel.swift index 59aae933..b5f60d67 100644 --- a/Core/Sources/SuggestionWidget/SuggestionPanelContent/CodeBlockSuggestionPanel.swift +++ b/Core/Sources/SuggestionWidget/SuggestionPanelContent/CodeBlockSuggestionPanel.swift @@ -6,6 +6,7 @@ struct CodeBlockSuggestionPanel: View { @Environment(\.colorScheme) var colorScheme @AppStorage(\.suggestionCodeFontSize) var fontSize @AppStorage(\.suggestionDisplayCompactMode) var suggestionDisplayCompactMode + @AppStorage(\.suggestionPresentationMode) var suggestionPresentationMode struct ToolBar: View { @ObservedObject var suggestion: CodeSuggestionProvider @@ -112,7 +113,12 @@ struct CodeBlockSuggestionPanel: View { ToolBar(suggestion: suggestion) } } - .xcodeStyleFrame() + .xcodeStyleFrame(cornerRadius: { + switch suggestionPresentationMode { + case .nearbyTextCursor: 6 + case .floatingWidget: nil + } + }()) } } From d98a48310b2c14c7cec906303d2528a8c6f0f948 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 16:36:26 +0800 Subject: [PATCH 15/22] Adjust chat panel UI --- Core/Sources/ChatGPTChatTab/ChatPanel.swift | 14 ++++- Core/Sources/ChatGPTChatTab/Styles.swift | 58 ++++++++++++++++++- .../ChatGPTChatTab/Views/BotMessage.swift | 2 +- .../ChatGPTChatTab/Views/Instructions.swift | 2 +- .../ChatGPTChatTab/Views/UserMessage.swift | 2 +- .../SuggestionWidget/ChatWindowView.swift | 1 - 6 files changed, 71 insertions(+), 8 deletions(-) diff --git a/Core/Sources/ChatGPTChatTab/ChatPanel.swift b/Core/Sources/ChatGPTChatTab/ChatPanel.swift index 2729b5e4..d9b443d4 100644 --- a/Core/Sources/ChatGPTChatTab/ChatPanel.swift +++ b/Core/Sources/ChatGPTChatTab/ChatPanel.swift @@ -18,7 +18,7 @@ public struct ChatPanel: View { Divider() ChatPanelInputArea(chat: chat) } - .background(.regularMaterial) + .background(.clear) .onAppear { chat.send(.appear) } } } @@ -86,13 +86,23 @@ struct ChatPanelMessages: View { } .modify { view in if #available(macOS 13.0, *) { - view.listRowSeparator(.hidden).listSectionSeparator(.hidden) + view + .listRowSeparator(.hidden) + .listSectionSeparator(.hidden) } else { view } } } .listStyle(.plain) + .listRowBackground(EmptyView()) + .modify { view in + if #available(macOS 13.0, *) { + view.scrollContentBackground(.hidden) + } else { + view + } + } .coordinateSpace(name: scrollSpace) .preference( key: ListHeightPreferenceKey.self, diff --git a/Core/Sources/ChatGPTChatTab/Styles.swift b/Core/Sources/ChatGPTChatTab/Styles.swift index ed1c981c..241c88f9 100644 --- a/Core/Sources/ChatGPTChatTab/Styles.swift +++ b/Core/Sources/ChatGPTChatTab/Styles.swift @@ -9,7 +9,7 @@ extension Color { if appearance.isDarkMode { return #colorLiteral(red: 0.1580096483, green: 0.1730263829, blue: 0.2026666105, alpha: 1) } - return .white + return #colorLiteral(red: 0.9896564803, green: 0.9896564803, blue: 0.9896564803, alpha: 1) })) } @@ -18,7 +18,7 @@ extension Color { if appearance.isDarkMode { return #colorLiteral(red: 0.2284317913, green: 0.2145925438, blue: 0.3214019983, alpha: 1) } - return #colorLiteral(red: 0.896820749, green: 0.8709097223, blue: 0.9766687925, alpha: 1) + return #colorLiteral(red: 0.957824412, green: 0.947133649, blue: 0.9906365955, alpha: 1) })) } } @@ -92,6 +92,60 @@ extension MarkdownUI.Theme { } } + static func instruction(fontSize: Double) -> MarkdownUI.Theme { + .gitHub.text { + ForegroundColor(.primary) + BackgroundColor(Color.clear) + FontSize(fontSize) + } + .code { + FontFamilyVariant(.monospaced) + FontSize(.em(0.85)) + BackgroundColor(Color.secondary.opacity(0.2)) + } + .codeBlock { configuration in + let wrapCode = UserDefaults.shared.value(for: \.wrapCodeInChatCodeBlock) + + if wrapCode { + configuration.label + .codeBlockLabelStyle() + .codeBlockStyle(configuration) + } else { + ScrollView(.horizontal) { + configuration.label + .codeBlockLabelStyle() + } + .workaroundForVerticalScrollingBugInMacOS() + .codeBlockStyle(configuration) + } + } + .table { configuration in + configuration.label + .fixedSize(horizontal: false, vertical: true) + .markdownTableBorderStyle(.init( + color: .init(nsColor: .separatorColor), + strokeStyle: .init(lineWidth: 1) + )) + .markdownTableBackgroundStyle( + .alternatingRows(Color.secondary.opacity(0.1), Color.secondary.opacity(0.2)) + ) + .markdownMargin(top: 0, bottom: 16) + } + .tableCell { configuration in + configuration.label + .markdownTextStyle { + if configuration.row == 0 { + FontWeight(.semibold) + } + BackgroundColor(nil) + } + .fixedSize(horizontal: false, vertical: true) + .padding(.vertical, 6) + .padding(.horizontal, 13) + .relativeLineSpacing(.em(0.25)) + } + } + static func functionCall(fontSize: Double) -> MarkdownUI.Theme { .gitHub.text { ForegroundColor(.secondary) diff --git a/Core/Sources/ChatGPTChatTab/Views/BotMessage.swift b/Core/Sources/ChatGPTChatTab/Views/BotMessage.swift index c8efac88..67457bf1 100644 --- a/Core/Sources/ChatGPTChatTab/Views/BotMessage.swift +++ b/Core/Sources/ChatGPTChatTab/Views/BotMessage.swift @@ -66,7 +66,7 @@ struct BotMessage: View { .stroke(Color(nsColor: .separatorColor), lineWidth: 1) } .padding(.leading, 8) - .shadow(color: .black.opacity(0.1), radius: 2) + .shadow(color: .black.opacity(0.05), radius: 6) .contextMenu { Button("Copy") { NSPasteboard.general.clearContents() diff --git a/Core/Sources/ChatGPTChatTab/Views/Instructions.swift b/Core/Sources/ChatGPTChatTab/Views/Instructions.swift index 2244a236..35097d08 100644 --- a/Core/Sources/ChatGPTChatTab/Views/Instructions.swift +++ b/Core/Sources/ChatGPTChatTab/Views/Instructions.swift @@ -71,7 +71,7 @@ struct Instruction: View { func body(content: Content) -> some View { content .textSelection(.enabled) - .markdownTheme(.custom(fontSize: chatFontSize)) + .markdownTheme(.instruction(fontSize: chatFontSize)) .opacity(0.8) .frame(maxWidth: .infinity, alignment: .leading) .padding() diff --git a/Core/Sources/ChatGPTChatTab/Views/UserMessage.swift b/Core/Sources/ChatGPTChatTab/Views/UserMessage.swift index 2fd67f42..c470cc4e 100644 --- a/Core/Sources/ChatGPTChatTab/Views/UserMessage.swift +++ b/Core/Sources/ChatGPTChatTab/Views/UserMessage.swift @@ -34,7 +34,7 @@ struct UserMessage: View { } .padding(.leading) .padding(.trailing, 8) - .shadow(color: .black.opacity(0.1), radius: 2) + .shadow(color: .black.opacity(0.05), radius: 6) .frame(maxWidth: .infinity, alignment: .trailing) .contextMenu { Button("Copy") { diff --git a/Core/Sources/SuggestionWidget/ChatWindowView.swift b/Core/Sources/SuggestionWidget/ChatWindowView.swift index cda1a21d..2855f142 100644 --- a/Core/Sources/SuggestionWidget/ChatWindowView.swift +++ b/Core/Sources/SuggestionWidget/ChatWindowView.swift @@ -43,7 +43,6 @@ struct ChatWindowView: View { } .xcodeStyleFrame(cornerRadius: 10) .ignoresSafeArea(edges: .top) - .background(.regularMaterial) .onChange(of: viewStore.state.isPanelDisplayed) { isDisplayed in toggleVisibility(isDisplayed) } From 0144241c87fd44a9222b13c05216ce96a0656562 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 17:42:26 +0800 Subject: [PATCH 16/22] Improve scroll to bottom behavior of chat panel --- Core/Sources/ChatGPTChatTab/Chat.swift | 36 ++++++++++++++++++++- Core/Sources/ChatGPTChatTab/ChatPanel.swift | 5 ++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/Core/Sources/ChatGPTChatTab/Chat.swift b/Core/Sources/ChatGPTChatTab/Chat.swift index 4d722d68..9b7f2ca8 100644 --- a/Core/Sources/ChatGPTChatTab/Chat.swift +++ b/Core/Sources/ChatGPTChatTab/Chat.swift @@ -226,9 +226,13 @@ struct Chat: ReducerProtocol { cancellable.cancel() } } - for await _ in stream { + let debouncedHistoryChange = TimedDebounceFunction(duration: 0.2) { await send(.historyChanged) } + + for await _ in stream { + await debouncedHistoryChange() + } }.cancellable(id: CancelID.observeHistoryChange(id), cancelInFlight: true) case .observeIsReceivingMessageChange: @@ -450,3 +454,33 @@ struct ChatMenu: ReducerProtocol { } } +private actor TimedDebounceFunction { + let duration: TimeInterval + let block: () async -> Void + + var task: Task? + var lastFireTime: Date = .init(timeIntervalSince1970: 0) + + init(duration: TimeInterval, block: @escaping () async -> Void) { + self.duration = duration + self.block = block + } + + func callAsFunction() async { + task?.cancel() + if lastFireTime.timeIntervalSinceNow < -duration { + await fire() + task = nil + } else { + task = Task.detached { [weak self, duration] in + try await Task.sleep(nanoseconds: UInt64(duration * 1_000_000_000)) + await self?.fire() + } + } + } + + func fire() async { + lastFireTime = Date() + await block() + } +} diff --git a/Core/Sources/ChatGPTChatTab/ChatPanel.swift b/Core/Sources/ChatGPTChatTab/ChatPanel.swift index d9b443d4..d66c0d25 100644 --- a/Core/Sources/ChatGPTChatTab/ChatPanel.swift +++ b/Core/Sources/ChatGPTChatTab/ChatPanel.swift @@ -228,7 +228,10 @@ struct ChatPanelMessages: View { if isInitialLoad { isInitialLoad = false } - scrollToBottom() + Task { + await Task.yield() + scrollToBottom() + } } } } From 03890a870a35ba998b6ef1bd1b31d5910876f92c Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 22:07:34 +0800 Subject: [PATCH 17/22] Update --- Pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pro b/Pro index 73744057..54bac65e 160000 --- a/Pro +++ b/Pro @@ -1 +1 @@ -Subproject commit 73744057e14bb107b35289022ae22efc7b46ce8c +Subproject commit 54bac65e5bcaf9b5dca31d312e4c90a08c30a6f9 From db6907fb4b23d159866764f32cc53e23fd8f72be Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 22:09:54 +0800 Subject: [PATCH 18/22] Bump build number --- Version.xcconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Version.xcconfig b/Version.xcconfig index 21e74a54..dfc69e7b 100644 --- a/Version.xcconfig +++ b/Version.xcconfig @@ -1,3 +1,3 @@ APP_VERSION = 0.31.2 -APP_BUILD = 338 +APP_BUILD = 339 From 38c3ee88d467537f9294593684c9f2f7fdaf1a4d Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 22:15:21 +0800 Subject: [PATCH 19/22] Adjust style --- Core/Sources/ChatGPTChatTab/Styles.swift | 2 +- Core/Sources/SuggestionWidget/Styles.swift | 2 +- Pro | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/Sources/ChatGPTChatTab/Styles.swift b/Core/Sources/ChatGPTChatTab/Styles.swift index 241c88f9..3f8d40c4 100644 --- a/Core/Sources/ChatGPTChatTab/Styles.swift +++ b/Core/Sources/ChatGPTChatTab/Styles.swift @@ -18,7 +18,7 @@ extension Color { if appearance.isDarkMode { return #colorLiteral(red: 0.2284317913, green: 0.2145925438, blue: 0.3214019983, alpha: 1) } - return #colorLiteral(red: 0.957824412, green: 0.947133649, blue: 0.9906365955, alpha: 1) + return #colorLiteral(red: 0.9458052187, green: 0.9311983998, blue: 0.9906365955, alpha: 1) })) } } diff --git a/Core/Sources/SuggestionWidget/Styles.swift b/Core/Sources/SuggestionWidget/Styles.swift index 393591ea..9f63b0f4 100644 --- a/Core/Sources/SuggestionWidget/Styles.swift +++ b/Core/Sources/SuggestionWidget/Styles.swift @@ -30,7 +30,7 @@ extension Color { if appearance.isDarkMode { return #colorLiteral(red: 0.2284317913, green: 0.2145925438, blue: 0.3214019983, alpha: 1) } - return #colorLiteral(red: 0.896820749, green: 0.8709097223, blue: 0.9766687925, alpha: 1) + return #colorLiteral(red: 0.9458052187, green: 0.9311983998, blue: 0.9906365955, alpha: 1) })) } } diff --git a/Pro b/Pro index 54bac65e..a26917fd 160000 --- a/Pro +++ b/Pro @@ -1 +1 @@ -Subproject commit 54bac65e5bcaf9b5dca31d312e4c90a08c30a6f9 +Subproject commit a26917fd375041c5ddec59f1d4458c0fdd04df01 From 4d1ae7c2e398076435a33582482622d66ae7e1d1 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 22:19:02 +0800 Subject: [PATCH 20/22] Add todo --- Core/Sources/SuggestionWidget/FeatureReducers/PromptToCode.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/Sources/SuggestionWidget/FeatureReducers/PromptToCode.swift b/Core/Sources/SuggestionWidget/FeatureReducers/PromptToCode.swift index ccc094b7..490c9cc6 100644 --- a/Core/Sources/SuggestionWidget/FeatureReducers/PromptToCode.swift +++ b/Core/Sources/SuggestionWidget/FeatureReducers/PromptToCode.swift @@ -187,6 +187,7 @@ public struct PromptToCode: ReducerProtocol { generateDescriptionRequirement: copiedState .generateDescriptionRequirement ) + #warning("TODO: make the action call debounced.") for try await fragment in stream { try Task.checkCancellation() await send(.modifyCodeChunkReceived( From c7d426f26eff07a8fda31935e44ac945cabf882f Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 22:19:08 +0800 Subject: [PATCH 21/22] Bump build number --- Version.xcconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Version.xcconfig b/Version.xcconfig index dfc69e7b..efa04634 100644 --- a/Version.xcconfig +++ b/Version.xcconfig @@ -1,3 +1,3 @@ APP_VERSION = 0.31.2 -APP_BUILD = 339 +APP_BUILD = 340 From 79e1e9b5007ba262aefb7bdad8791eda15dc2cc3 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 14 Mar 2024 22:28:45 +0800 Subject: [PATCH 22/22] Update appcast.xml --- appcast.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/appcast.xml b/appcast.xml index 234647e1..294301d0 100644 --- a/appcast.xml +++ b/appcast.xml @@ -2,6 +2,18 @@ Copilot for Xcode + + 0.31.2 + Thu, 14 Mar 2024 22:26:51 +0800 + 340 + 0.31.2 + 12.0 + + https://github.com/intitni/CopilotForXcode/releases/tag/0.31.2 + + + + 0.31.1 Wed, 13 Mar 2024 21:24:28 +0800