From 3f328dd86e715fb8aeb46f3a232a4ad20367b15d Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 30 May 2024 17:53:50 +0800 Subject: [PATCH 01/11] Add debugging logs --- Pro | 2 +- Tool/Sources/Logger/Logger.swift | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Pro b/Pro index b915eb29..f056f7c4 160000 --- a/Pro +++ b/Pro @@ -1 +1 @@ -Subproject commit b915eb299fd44668902a3125c257af3e8f302d72 +Subproject commit f056f7c4a02696ad63a975a3cad62eae8b01aaa4 diff --git a/Tool/Sources/Logger/Logger.swift b/Tool/Sources/Logger/Logger.swift index 8a7c1f8c..390e54d5 100644 --- a/Tool/Sources/Logger/Logger.swift +++ b/Tool/Sources/Logger/Logger.swift @@ -23,6 +23,7 @@ public final class Logger { public static let license = Logger(category: "License") public static let `extension` = Logger(category: "Extension") public static let communicationBridge = Logger(category: "CommunicationBridge") + public static let debug = Logger(category: "Debug") #if DEBUG /// Use a temp logger to log something temporary. I won't be available in release builds. public static let temp = Logger(category: "Temp") From 62613e921bc060d6bd933d64bb6d490f39d83ca0 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 30 May 2024 17:58:13 +0800 Subject: [PATCH 02/11] Fix that the GitHub Copilot language server was not terminating when the workspace closed --- .../GitHubCopilotExtension.swift | 2 +- .../GitHubCopilotWorkspacePlugin.swift | 13 ++++++++++--- .../LanguageServer/CopilotLocalProcessServer.swift | 4 ++++ .../LanguageServer/GitHubCopilotService.swift | 4 ++++ Tool/Sources/Workspace/Workspace.swift | 2 +- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Tool/Sources/GitHubCopilotService/GitHubCopilotExtension.swift b/Tool/Sources/GitHubCopilotService/GitHubCopilotExtension.swift index a9083fec..867fc82e 100644 --- a/Tool/Sources/GitHubCopilotService/GitHubCopilotExtension.swift +++ b/Tool/Sources/GitHubCopilotService/GitHubCopilotExtension.swift @@ -141,7 +141,7 @@ final class ServiceLocator { guard let workspace = workspacePool.workspaces[workspace.workspaceURL], let plugin = workspace.plugin(for: GitHubCopilotWorkspacePlugin.self) else { return nil } - return plugin.gitHubCopilotService + return await plugin.gitHubCopilotService } } diff --git a/Tool/Sources/GitHubCopilotService/GitHubCopilotWorkspacePlugin.swift b/Tool/Sources/GitHubCopilotService/GitHubCopilotWorkspacePlugin.swift index a5b71740..0c3b8615 100644 --- a/Tool/Sources/GitHubCopilotService/GitHubCopilotWorkspacePlugin.swift +++ b/Tool/Sources/GitHubCopilotService/GitHubCopilotWorkspacePlugin.swift @@ -3,7 +3,8 @@ import Logger import Workspace public final class GitHubCopilotWorkspacePlugin: WorkspacePlugin { - var _gitHubCopilotService: GitHubCopilotService? + private var _gitHubCopilotService: GitHubCopilotService? + @GitHubCopilotSuggestionActor var gitHubCopilotService: GitHubCopilotService? { if let service = _gitHubCopilotService { return service } do { @@ -15,14 +16,19 @@ public final class GitHubCopilotWorkspacePlugin: WorkspacePlugin { } deinit { - if let gitHubCopilotService { - Task { await gitHubCopilotService.terminate() } + if let _gitHubCopilotService { + Task { await _gitHubCopilotService.terminate() } } } + @GitHubCopilotSuggestionActor func createGitHubCopilotService() throws -> GitHubCopilotService { let newService = try GitHubCopilotService(projectRootURL: projectRootURL) _gitHubCopilotService = newService + newService.localProcessServer?.terminationHandler = { [weak self] in + Logger.gitHubCopilot.error("GitHub Copilot language server terminated") + self?.terminate() + } Task { try await Task.sleep(nanoseconds: 1_000_000_000) finishLaunchingService() @@ -30,6 +36,7 @@ public final class GitHubCopilotWorkspacePlugin: WorkspacePlugin { return newService } + @GitHubCopilotSuggestionActor func finishLaunchingService() { guard let workspace, let _gitHubCopilotService else { return } Task { diff --git a/Tool/Sources/GitHubCopilotService/LanguageServer/CopilotLocalProcessServer.swift b/Tool/Sources/GitHubCopilotService/LanguageServer/CopilotLocalProcessServer.swift index 40e7ac4f..fd210c16 100644 --- a/Tool/Sources/GitHubCopilotService/LanguageServer/CopilotLocalProcessServer.swift +++ b/Tool/Sources/GitHubCopilotService/LanguageServer/CopilotLocalProcessServer.swift @@ -84,6 +84,10 @@ class CopilotLocalProcessServer { get { return wrappedServer?.logMessages ?? false } set { wrappedServer?.logMessages = newValue } } + + func terminate() { + process.terminate() + } } extension CopilotLocalProcessServer: LanguageServerProtocol.Server { diff --git a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift index 04bb977d..3eb314c9 100644 --- a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift +++ b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift @@ -95,6 +95,10 @@ public class GitHubCopilotBaseService { let projectRootURL: URL var server: GitHubCopilotLSP var localProcessServer: CopilotLocalProcessServer? + + deinit { + localProcessServer?.terminate() + } init(designatedServer: GitHubCopilotLSP) { projectRootURL = URL(fileURLWithPath: "/") diff --git a/Tool/Sources/Workspace/Workspace.swift b/Tool/Sources/Workspace/Workspace.swift index a7937756..2184c779 100644 --- a/Tool/Sources/Workspace/Workspace.swift +++ b/Tool/Sources/Workspace/Workspace.swift @@ -74,7 +74,7 @@ public final class Workspace { public let openedFileRecoverableStorage: OpenedFileRecoverableStorage public private(set) var lastLastUpdateTime = Environment.now() public var isExpired: Bool { - Environment.now().timeIntervalSince(lastLastUpdateTime) > 60 * 60 * 1 + Environment.now().timeIntervalSince(lastLastUpdateTime) > 30 * 60 * 1 } public private(set) var filespaces = [URL: Filespace]() From 0e59aa9c85ee153cfde40b0da686bebf9a26cc91 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 30 May 2024 17:58:20 +0800 Subject: [PATCH 03/11] Fix id tracking --- .../LanguageServer/CopilotLocalProcessServer.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tool/Sources/GitHubCopilotService/LanguageServer/CopilotLocalProcessServer.swift b/Tool/Sources/GitHubCopilotService/LanguageServer/CopilotLocalProcessServer.swift index fd210c16..0a8dba2c 100644 --- a/Tool/Sources/GitHubCopilotService/LanguageServer/CopilotLocalProcessServer.swift +++ b/Tool/Sources/GitHubCopilotService/LanguageServer/CopilotLocalProcessServer.swift @@ -45,7 +45,8 @@ class CopilotLocalProcessServer { // we need to get the request IDs from a custom transport before the data // is written to the language server. customTransport.onWriteRequest = { [weak self] request in - if request.method == "getCompletionsCycling" { + if request.method == "getCompletionsCycling" + || request.method == "textDocument/inlineCompletion" { Task { @MainActor [weak self] in self?.ongoingCompletionRequestIDs.append(request.id) } From 202f30f5ddf287094c36e85304d688dd581506a1 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 30 May 2024 18:04:48 +0800 Subject: [PATCH 04/11] Fix duplicated Codeium language server --- Tool/Sources/CodeiumService/CodeiumExtension.swift | 7 ++++++- Tool/Sources/CodeiumService/CodeiumWorkspacePlugin.swift | 9 ++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Tool/Sources/CodeiumService/CodeiumExtension.swift b/Tool/Sources/CodeiumService/CodeiumExtension.swift index ee3f18f6..05464478 100644 --- a/Tool/Sources/CodeiumService/CodeiumExtension.swift +++ b/Tool/Sources/CodeiumService/CodeiumExtension.swift @@ -5,6 +5,11 @@ import Logger import Preferences import Workspace +@globalActor public enum CodeiumActor { + public actor TheActor {} + public static let shared = TheActor() +} + public final class CodeiumExtension: BuiltinExtension { public var suggestionServiceId: Preferences.BuiltInSuggestionFeatureProvider { .codeium } @@ -119,7 +124,7 @@ final class ServiceLocator { guard let workspace = workspacePool.workspaces[workspace.workspaceURL], let plugin = workspace.plugin(for: CodeiumWorkspacePlugin.self) else { return nil } - return plugin.codeiumService + return await plugin.codeiumService } } diff --git a/Tool/Sources/CodeiumService/CodeiumWorkspacePlugin.swift b/Tool/Sources/CodeiumService/CodeiumWorkspacePlugin.swift index 62093950..5e8d3b32 100644 --- a/Tool/Sources/CodeiumService/CodeiumWorkspacePlugin.swift +++ b/Tool/Sources/CodeiumService/CodeiumWorkspacePlugin.swift @@ -3,7 +3,8 @@ import Logger import Workspace public final class CodeiumWorkspacePlugin: WorkspacePlugin { - var _codeiumService: CodeiumService? + private var _codeiumService: CodeiumService? + @CodeiumActor var codeiumService: CodeiumService? { if let service = _codeiumService { return service } do { @@ -15,11 +16,12 @@ public final class CodeiumWorkspacePlugin: WorkspacePlugin { } deinit { - if let codeiumService { - codeiumService.terminate() + if let _codeiumService { + _codeiumService.terminate() } } + @CodeiumActor func createCodeiumService() throws -> CodeiumService { let newService = try CodeiumService( projectRootURL: projectRootURL, @@ -32,6 +34,7 @@ public final class CodeiumWorkspacePlugin: WorkspacePlugin { return newService } + @CodeiumActor func finishLaunchingService() { guard let workspace, let _codeiumService else { return } Task { From e2d195502b1d037dc8a34192aa87f5d5371cae9b Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 30 May 2024 18:09:55 +0800 Subject: [PATCH 05/11] Add handler for termination --- .../CodeiumService/CodeiumService.swift | 18 +++++++++++++----- .../CodeiumWorkspacePlugin.swift | 3 +++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Tool/Sources/CodeiumService/CodeiumService.swift b/Tool/Sources/CodeiumService/CodeiumService.swift index d0706bf9..62ddaac4 100644 --- a/Tool/Sources/CodeiumService/CodeiumService.swift +++ b/Tool/Sources/CodeiumService/CodeiumService.swift @@ -48,6 +48,7 @@ public class CodeiumService { var cancellationCounter: UInt64 = 0 let openedDocumentPool = OpenedDocumentPool() let onServiceLaunched: () -> Void + let onServiceTerminated: () -> Void let languageServerURL: URL let supportURL: URL @@ -63,13 +64,19 @@ public class CodeiumService { projectRootURL = URL(fileURLWithPath: "/") server = designatedServer onServiceLaunched = {} + onServiceTerminated = {} languageServerURL = URL(fileURLWithPath: "/") supportURL = URL(fileURLWithPath: "/") } - public init(projectRootURL: URL, onServiceLaunched: @escaping () -> Void) throws { + public init( + projectRootURL: URL, + onServiceLaunched: @escaping () -> Void, + onServiceTerminated: @escaping () -> Void + ) throws { self.projectRootURL = projectRootURL self.onServiceLaunched = onServiceLaunched + self.onServiceTerminated = onServiceTerminated let urls = try CodeiumService.createFoldersIfNeeded() languageServerURL = urls.executableURL.appendingPathComponent("language_server") supportURL = urls.supportURL @@ -117,6 +124,7 @@ public class CodeiumService { self?.heartbeatTask?.cancel() self?.requestCounter = 0 self?.cancellationCounter = 0 + self?.onServiceTerminated() Logger.codeium.info("Language server is terminated, will be restarted when needed.") } @@ -186,7 +194,7 @@ extension CodeiumService { throw E() } var ideVersion = await XcodeInspector.shared.safe.latestActiveXcode?.version - ?? fallbackXcodeVersion + ?? fallbackXcodeVersion let versionNumberSegmentCount = ideVersion.split(separator: ".").count if versionNumberSegmentCount == 2 { ideVersion += ".0" @@ -237,8 +245,8 @@ extension CodeiumService: CodeiumSuggestionServiceType { let relativePath = getRelativePath(of: fileURL) let task = Task { - let request = await CodeiumRequest.GetCompletion(requestBody: .init( - metadata: try getMetadata(), + let request = try await CodeiumRequest.GetCompletion(requestBody: .init( + metadata: getMetadata(), document: .init( absolute_path: fileURL.path, relative_path: relativePath, @@ -266,7 +274,7 @@ extension CodeiumService: CodeiumSuggestionServiceType { try Task.checkCancellation() - let result = try await (try await setupServerIfNeeded()).sendRequest(request) + let result = try await (await setupServerIfNeeded()).sendRequest(request) try Task.checkCancellation() diff --git a/Tool/Sources/CodeiumService/CodeiumWorkspacePlugin.swift b/Tool/Sources/CodeiumService/CodeiumWorkspacePlugin.swift index 5e8d3b32..4d9d58d5 100644 --- a/Tool/Sources/CodeiumService/CodeiumWorkspacePlugin.swift +++ b/Tool/Sources/CodeiumService/CodeiumWorkspacePlugin.swift @@ -28,6 +28,9 @@ public final class CodeiumWorkspacePlugin: WorkspacePlugin { onServiceLaunched: { [weak self] in self?.finishLaunchingService() + }, + onServiceTerminated: { + // start handled in the service. } ) _codeiumService = newService From e82900c6eb9f76ffbca50fd01045e93f7f9ce7fb Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 30 May 2024 18:21:56 +0800 Subject: [PATCH 06/11] Bump GitHub Copilot language server to 1.33.0 --- .../LanguageServer/GitHubCopilotInstallationManager.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotInstallationManager.swift b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotInstallationManager.swift index 069d2c0b..efd8576b 100644 --- a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotInstallationManager.swift +++ b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotInstallationManager.swift @@ -5,12 +5,12 @@ public struct GitHubCopilotInstallationManager { private static var isInstalling = false static var downloadURL: URL { - let commitHash = "25feddf8e3aa79f0573c8f43ddb13c44c530cfa5" + let commitHash = "c79d711cbf7c6672c6c57d6df7c5ab7b6cac2b7a" let link = "https://github.com/github/copilot.vim/archive/\(commitHash).zip" return URL(string: link)! } - static let latestSupportedVersion = "1.32.0" + static let latestSupportedVersion = "1.33.0" public init() {} From 69c96eaa5fe368cf3df07be076d02a204978b18d Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 30 May 2024 20:12:40 +0800 Subject: [PATCH 07/11] Tweak update process --- Copilot for Xcode/App.swift | 28 +++++++++++-- Core/Sources/HostApp/TabContainer.swift | 5 ++- Core/Sources/Service/XPCService.swift | 7 ++++ .../Sources/UpdateChecker/UpdateChecker.swift | 39 ++++++++++++++++++- ExtensionService/AppDelegate.swift | 20 +++++++--- Pro | 2 +- .../XPCShared/XPCExtensionService.swift | 23 +++++++++++ .../XPCShared/XPCServiceProtocol.swift | 1 + 8 files changed, 113 insertions(+), 12 deletions(-) diff --git a/Copilot for Xcode/App.swift b/Copilot for Xcode/App.swift index 094e32d5..99a0a044 100644 --- a/Copilot for Xcode/App.swift +++ b/Copilot for Xcode/App.swift @@ -6,10 +6,22 @@ import UpdateChecker import XPCShared struct VisualEffect: NSViewRepresentable { - func makeNSView(context: Self.Context) -> NSView { return NSVisualEffectView() } - func updateNSView(_ nsView: NSView, context: Context) { } + func makeNSView(context: Self.Context) -> NSView { return NSVisualEffectView() } + func updateNSView(_ nsView: NSView, context: Context) {} } +class TheUpdateCheckerDelegate: UpdateCheckerDelegate { + func prepareForRelaunch(finish: @escaping () -> Void) { + Task { + let service = try? getService() + try? await service?.quitService() + finish() + } + } +} + +let updateCheckerDelegate = TheUpdateCheckerDelegate() + @main struct CopilotForXcodeApp: App { var body: some Scene { @@ -20,7 +32,17 @@ struct CopilotForXcodeApp: App { .onAppear { UserDefaults.setupDefaultSettings() } - .environment(\.updateChecker, UpdateChecker(hostBundle: Bundle.main)) + .environment( + \.updateChecker, + { + let checker = UpdateChecker( + hostBundle: Bundle.main, + shouldAutomaticallyCheckForUpdate: false + ) + checker.updateCheckerDelegate = updateCheckerDelegate + return checker + }() + ) } } } diff --git a/Core/Sources/HostApp/TabContainer.swift b/Core/Sources/HostApp/TabContainer.swift index 752158ea..30ae0187 100644 --- a/Core/Sources/HostApp/TabContainer.swift +++ b/Core/Sources/HostApp/TabContainer.swift @@ -215,7 +215,10 @@ private extension EnvironmentValues { } struct UpdateCheckerKey: EnvironmentKey { - static var defaultValue: UpdateChecker = .init(hostBundle: nil) + static var defaultValue: UpdateChecker = .init( + hostBundle: nil, + shouldAutomaticallyCheckForUpdate: false + ) } public extension EnvironmentValues { diff --git a/Core/Sources/Service/XPCService.swift b/Core/Sources/Service/XPCService.swift index 1cffcc7a..9c358ada 100644 --- a/Core/Sources/Service/XPCService.swift +++ b/Core/Sources/Service/XPCService.swift @@ -195,6 +195,13 @@ public class XPCService: NSObject, XPCServiceProtocol { reply() NotificationCenter.default.post(name: .init(name), object: nil) } + + public func quit(reply: @escaping () -> Void) { + Task { + await Service.shared.prepareForExit() + reply() + } + } // MARK: - Requests diff --git a/Core/Sources/UpdateChecker/UpdateChecker.swift b/Core/Sources/UpdateChecker/UpdateChecker.swift index a9d7b88b..4bd17200 100644 --- a/Core/Sources/UpdateChecker/UpdateChecker.swift +++ b/Core/Sources/UpdateChecker/UpdateChecker.swift @@ -5,15 +5,25 @@ import Sparkle public final class UpdateChecker { let updater: SPUUpdater let hostBundleFound: Bool - let delegate = UpdaterDelegate() + let delegate: UpdaterDelegate + public weak var updateCheckerDelegate: UpdateCheckerDelegate? { + get { delegate.updateCheckerDelegate } + set { delegate.updateCheckerDelegate = newValue } + } - public init(hostBundle: Bundle?) { + public init( + hostBundle: Bundle?, + shouldAutomaticallyCheckForUpdate: Bool + ) { if hostBundle == nil { hostBundleFound = false Logger.updateChecker.error("Host bundle not found") } else { hostBundleFound = true } + delegate = .init( + shouldAutomaticallyCheckForUpdate: shouldAutomaticallyCheckForUpdate + ) updater = SPUUpdater( hostBundle: hostBundle ?? Bundle.main, applicationBundle: Bundle.main, @@ -37,7 +47,32 @@ public final class UpdateChecker { } } +public protocol UpdateCheckerDelegate: AnyObject { + func prepareForRelaunch(finish: @escaping () -> Void) +} + class UpdaterDelegate: NSObject, SPUUpdaterDelegate { + let shouldAutomaticallyCheckForUpdate: Bool + weak var updateCheckerDelegate: UpdateCheckerDelegate? + + init(shouldAutomaticallyCheckForUpdate: Bool) { + self.shouldAutomaticallyCheckForUpdate = shouldAutomaticallyCheckForUpdate + } + + func updater(_ updater: SPUUpdater, mayPerform updateCheck: SPUUpdateCheck) throws { + if !shouldAutomaticallyCheckForUpdate, updateCheck == .updatesInBackground { + throw CancellationError() + } + } + + func updater(_ updater: SPUUpdater, shouldPostponeRelaunchForUpdate item: SUAppcastItem, untilInvokingBlock installHandler: @escaping () -> Void) -> Bool { + if let updateCheckerDelegate { + updateCheckerDelegate.prepareForRelaunch(finish: installHandler) + return true + } + return false + } + func allowedChannels(for updater: SPUUpdater) -> Set { if UserDefaults.shared.value(for: \.installBetaBuilds) { Set(["beta"]) diff --git a/ExtensionService/AppDelegate.swift b/ExtensionService/AppDelegate.swift index 3f5a8c3f..c63b9a77 100644 --- a/ExtensionService/AppDelegate.swift +++ b/ExtensionService/AppDelegate.swift @@ -21,15 +21,16 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { let service = Service.shared var statusBarItem: NSStatusItem! var xpcController: XPCController? - let updateChecker = - UpdateChecker( - hostBundle: locateHostBundleURL(url: Bundle.main.bundleURL) - .flatMap(Bundle.init(url:)) - ) + let updateChecker = UpdateChecker( + hostBundle: locateHostBundleURL(url: Bundle.main.bundleURL) + .flatMap(Bundle.init(url:)), + shouldAutomaticallyCheckForUpdate: true + ) func applicationDidFinishLaunching(_: Notification) { if ProcessInfo.processInfo.environment["IS_UNIT_TEST"] == "YES" { return } _ = XcodeInspector.shared + updateChecker.updateCheckerDelegate = self service.start() AXIsProcessTrustedWithOptions([ kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true, @@ -138,6 +139,15 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { } } +extension AppDelegate: UpdateCheckerDelegate { + func prepareForRelaunch(finish: @escaping () -> Void) { + Task { + await service.prepareForExit() + finish() + } + } +} + extension NSRunningApplication { var isUserOfService: Bool { [ diff --git a/Pro b/Pro index f056f7c4..d58fa18d 160000 --- a/Pro +++ b/Pro @@ -1 +1 @@ -Subproject commit f056f7c4a02696ad63a975a3cad62eae8b01aaa4 +Subproject commit d58fa18d0bd388aaa54f13ae4aad9853221bff1f diff --git a/Tool/Sources/XPCShared/XPCExtensionService.swift b/Tool/Sources/XPCShared/XPCExtensionService.swift index 7b2ab067..5003aaf2 100644 --- a/Tool/Sources/XPCShared/XPCExtensionService.swift +++ b/Tool/Sources/XPCShared/XPCExtensionService.swift @@ -161,6 +161,15 @@ public class XPCExtensionService { { service in { service.customCommand(id: id, editorContent: $0, withReply: $1) } } ) } + + public func quitService() async throws { + try await withXPCServiceConnectedWithoutLaunching { + service, continuation in + service.quit { + continuation.resume(()) + } + } + } public func postNotification(name: String) async throws { try await withXPCServiceConnected { @@ -254,6 +263,20 @@ extension XPCExtensionService { } } } + + @XPCServiceActor + private func withXPCServiceConnectedWithoutLaunching( + _ fn: @escaping (XPCServiceProtocol, AutoFinishContinuation) -> Void + ) async throws -> T { + if let service, let connection = service.connection { + do { + return try await XPCShared.withXPCServiceConnected(connection: connection, fn) + } catch { + throw XPCExtensionServiceError.xpcServiceError(error) + } + } + throw XPCExtensionServiceError.failedToCreateXPCConnection + } @XPCServiceActor private func suggestionRequest( diff --git a/Tool/Sources/XPCShared/XPCServiceProtocol.swift b/Tool/Sources/XPCShared/XPCServiceProtocol.swift index d2992270..e659db45 100644 --- a/Tool/Sources/XPCShared/XPCServiceProtocol.swift +++ b/Tool/Sources/XPCShared/XPCServiceProtocol.swift @@ -56,6 +56,7 @@ public protocol XPCServiceProtocol { func getXPCServiceAccessibilityPermission(withReply reply: @escaping (Bool) -> Void) func postNotification(name: String, withReply reply: @escaping () -> Void) func send(endpoint: String, requestBody: Data, reply: @escaping (Data?, Error?) -> Void) + func quit(reply: @escaping () -> Void) } public struct NoResponse: Codable { From a29ceb8b1bb91729f26919b66d28aa165fdcb08a Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 30 May 2024 21:42:36 +0800 Subject: [PATCH 08/11] Update handler --- .../LanguageServer/GitHubCopilotService.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift index 3eb314c9..6d7f17cf 100644 --- a/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift +++ b/Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift @@ -187,8 +187,8 @@ public class GitHubCopilotBaseService { let localServer = CopilotLocalProcessServer(executionParameters: executionParams) localServer.logMessages = UserDefaults.shared.value(for: \.gitHubCopilotVerboseLog) - localServer.notificationHandler = { _, respond in - respond(.timeout) + localServer.notificationHandler = { notification, respond in + respond(.handlerUnavailable(notification.method.rawValue)) } let server = InitializingServer(server: localServer) From 446f79f4e7390d95f89b5b0f9bd03d66993f48ab Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Thu, 30 May 2024 23:22:14 +0800 Subject: [PATCH 09/11] Add logs --- Core/Sources/HostApp/DebugView.swift | 5 ++++ Core/Sources/Service/Service.swift | 2 ++ .../Sources/UpdateChecker/UpdateChecker.swift | 27 +++++++++++++++---- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Core/Sources/HostApp/DebugView.swift b/Core/Sources/HostApp/DebugView.swift index 1f210e96..85c9ed4d 100644 --- a/Core/Sources/HostApp/DebugView.swift +++ b/Core/Sources/HostApp/DebugView.swift @@ -34,6 +34,7 @@ final class DebugSettings: ObservableObject { struct DebugSettingsView: View { @StateObject var settings = DebugSettings() + @Environment(\.updateChecker) var updateChecker var body: some View { ScrollView { @@ -134,6 +135,10 @@ struct DebugSettingsView: View { ) { Text("Use Cloudflare domain name for license check") } + + Button("Reset update cycle") { + updateChecker.resetUpdateCycle() + } } } .frame(maxWidth: .infinity) diff --git a/Core/Sources/Service/Service.swift b/Core/Sources/Service/Service.swift index fa62b47e..04b8bd9c 100644 --- a/Core/Sources/Service/Service.swift +++ b/Core/Sources/Service/Service.swift @@ -4,6 +4,7 @@ import Combine import Dependencies import Foundation import GitHubCopilotService +import Logger import SuggestionService import Toast import Workspace @@ -103,6 +104,7 @@ public final class Service { @MainActor public func prepareForExit() async { + Logger.service.info("Prepare for exit.") #if canImport(ProService) proService.prepareForExit() #endif diff --git a/Core/Sources/UpdateChecker/UpdateChecker.swift b/Core/Sources/UpdateChecker/UpdateChecker.swift index 4bd17200..7619d579 100644 --- a/Core/Sources/UpdateChecker/UpdateChecker.swift +++ b/Core/Sources/UpdateChecker/UpdateChecker.swift @@ -40,6 +40,10 @@ public final class UpdateChecker { public func checkForUpdates() { updater.checkForUpdates() } + + public func resetUpdateCycle() { + updater.resetUpdateCycleAfterShortDelay() + } public var automaticallyChecksForUpdates: Bool { get { updater.automaticallyChecksForUpdates } @@ -60,18 +64,31 @@ class UpdaterDelegate: NSObject, SPUUpdaterDelegate { } func updater(_ updater: SPUUpdater, mayPerform updateCheck: SPUUpdateCheck) throws { - if !shouldAutomaticallyCheckForUpdate, updateCheck == .updatesInBackground { - throw CancellationError() - } + // Not sure how it works +// if !shouldAutomaticallyCheckForUpdate, updateCheck == .updatesInBackground { +// throw CancellationError() +// } } - - func updater(_ updater: SPUUpdater, shouldPostponeRelaunchForUpdate item: SUAppcastItem, untilInvokingBlock installHandler: @escaping () -> Void) -> Bool { + + func updater( + _ updater: SPUUpdater, + shouldPostponeRelaunchForUpdate item: SUAppcastItem, + untilInvokingBlock installHandler: @escaping () -> Void + ) -> Bool { if let updateCheckerDelegate { updateCheckerDelegate.prepareForRelaunch(finish: installHandler) return true } return false } + + func updater(_ updater: SPUUpdater, willScheduleUpdateCheckAfterDelay delay: TimeInterval) { + Logger.updateChecker.info("Will schedule update check after delay: \(delay)") + } + + func updaterWillNotScheduleUpdateCheck(_ updater: SPUUpdater) { + Logger.updateChecker.info("Will not schedule update check") + } func allowedChannels(for updater: SPUUpdater) -> Set { if UserDefaults.shared.value(for: \.installBetaBuilds) { From 7c663b0c87cdf82436674de1c9f21a2daa8cdfee Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Fri, 31 May 2024 00:57:45 +0800 Subject: [PATCH 10/11] Update appcast.xml --- appcast.xml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/appcast.xml b/appcast.xml index 9aa6f8f5..8cccd8f8 100644 --- a/appcast.xml +++ b/appcast.xml @@ -2,6 +2,15 @@ Copilot for Xcode + + 0.33.2 + Fri, 31 May 2024 00:26:22 +0800 + 385 + 0.33.2 + 12.0 + https://github.com/intitni/CopilotForXcode/releases/tag/0.33.2 + + 0.33.1 Mon, 27 May 2024 16:28:20 +0800 @@ -32,16 +41,5 @@ - - 0.32.3 - Wed, 01 May 2024 15:35:26 +0800 - 367 - 0.32.3 - 12.0 - - https://github.com/intitni/CopilotForXcode/releases/tag/0.32.3 - - - \ No newline at end of file From a3332c52254910efa626ee80a2ff57d37bea2922 Mon Sep 17 00:00:00 2001 From: Shx Guo Date: Fri, 31 May 2024 00:57:52 +0800 Subject: [PATCH 11/11] Bump version to 0.33.2 --- Version.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Version.xcconfig b/Version.xcconfig index 5a72de69..acf540d2 100644 --- a/Version.xcconfig +++ b/Version.xcconfig @@ -1,3 +1,3 @@ -APP_VERSION = 0.33.1 -APP_BUILD = 382 +APP_VERSION = 0.33.2 +APP_BUILD = 385