Skip to content

Commit d9e7e09

Browse files
committed
Merge tag '0.33.2' into develop
2 parents f66d99b + c779a8c commit d9e7e09

22 files changed

Lines changed: 203 additions & 44 deletions

Copilot for Xcode/App.swift

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,22 @@ import UpdateChecker
66
import XPCShared
77

88
struct VisualEffect: NSViewRepresentable {
9-
func makeNSView(context: Self.Context) -> NSView { return NSVisualEffectView() }
10-
func updateNSView(_ nsView: NSView, context: Context) { }
9+
func makeNSView(context: Self.Context) -> NSView { return NSVisualEffectView() }
10+
func updateNSView(_ nsView: NSView, context: Context) {}
1111
}
1212

13+
class TheUpdateCheckerDelegate: UpdateCheckerDelegate {
14+
func prepareForRelaunch(finish: @escaping () -> Void) {
15+
Task {
16+
let service = try? getService()
17+
try? await service?.quitService()
18+
finish()
19+
}
20+
}
21+
}
22+
23+
let updateCheckerDelegate = TheUpdateCheckerDelegate()
24+
1325
@main
1426
struct CopilotForXcodeApp: App {
1527
var body: some Scene {
@@ -20,7 +32,17 @@ struct CopilotForXcodeApp: App {
2032
.onAppear {
2133
UserDefaults.setupDefaultSettings()
2234
}
23-
.environment(\.updateChecker, UpdateChecker(hostBundle: Bundle.main))
35+
.environment(
36+
\.updateChecker,
37+
{
38+
let checker = UpdateChecker(
39+
hostBundle: Bundle.main,
40+
shouldAutomaticallyCheckForUpdate: false
41+
)
42+
checker.updateCheckerDelegate = updateCheckerDelegate
43+
return checker
44+
}()
45+
)
2446
}
2547
}
2648
}

Core/Sources/HostApp/DebugView.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ final class DebugSettings: ObservableObject {
3434

3535
struct DebugSettingsView: View {
3636
@StateObject var settings = DebugSettings()
37+
@Environment(\.updateChecker) var updateChecker
3738

3839
var body: some View {
3940
ScrollView {
@@ -134,6 +135,10 @@ struct DebugSettingsView: View {
134135
) {
135136
Text("Use Cloudflare domain name for license check")
136137
}
138+
139+
Button("Reset update cycle") {
140+
updateChecker.resetUpdateCycle()
141+
}
137142
}
138143
}
139144
.frame(maxWidth: .infinity)

Core/Sources/HostApp/TabContainer.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,10 @@ private extension EnvironmentValues {
215215
}
216216

217217
struct UpdateCheckerKey: EnvironmentKey {
218-
static var defaultValue: UpdateChecker = .init(hostBundle: nil)
218+
static var defaultValue: UpdateChecker = .init(
219+
hostBundle: nil,
220+
shouldAutomaticallyCheckForUpdate: false
221+
)
219222
}
220223

221224
public extension EnvironmentValues {

Core/Sources/Service/Service.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Combine
44
import Dependencies
55
import Foundation
66
import GitHubCopilotService
7+
import Logger
78
import SuggestionService
89
import Toast
910
import Workspace
@@ -103,6 +104,7 @@ public final class Service {
103104

104105
@MainActor
105106
public func prepareForExit() async {
107+
Logger.service.info("Prepare for exit.")
106108
#if canImport(ProService)
107109
proService.prepareForExit()
108110
#endif

Core/Sources/Service/XPCService.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,13 @@ public class XPCService: NSObject, XPCServiceProtocol {
195195
reply()
196196
NotificationCenter.default.post(name: .init(name), object: nil)
197197
}
198+
199+
public func quit(reply: @escaping () -> Void) {
200+
Task {
201+
await Service.shared.prepareForExit()
202+
reply()
203+
}
204+
}
198205

199206
// MARK: - Requests
200207

Core/Sources/UpdateChecker/UpdateChecker.swift

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,25 @@ import Sparkle
55
public final class UpdateChecker {
66
let updater: SPUUpdater
77
let hostBundleFound: Bool
8-
let delegate = UpdaterDelegate()
8+
let delegate: UpdaterDelegate
9+
public weak var updateCheckerDelegate: UpdateCheckerDelegate? {
10+
get { delegate.updateCheckerDelegate }
11+
set { delegate.updateCheckerDelegate = newValue }
12+
}
913

10-
public init(hostBundle: Bundle?) {
14+
public init(
15+
hostBundle: Bundle?,
16+
shouldAutomaticallyCheckForUpdate: Bool
17+
) {
1118
if hostBundle == nil {
1219
hostBundleFound = false
1320
Logger.updateChecker.error("Host bundle not found")
1421
} else {
1522
hostBundleFound = true
1623
}
24+
delegate = .init(
25+
shouldAutomaticallyCheckForUpdate: shouldAutomaticallyCheckForUpdate
26+
)
1727
updater = SPUUpdater(
1828
hostBundle: hostBundle ?? Bundle.main,
1929
applicationBundle: Bundle.main,
@@ -30,14 +40,56 @@ public final class UpdateChecker {
3040
public func checkForUpdates() {
3141
updater.checkForUpdates()
3242
}
43+
44+
public func resetUpdateCycle() {
45+
updater.resetUpdateCycleAfterShortDelay()
46+
}
3347

3448
public var automaticallyChecksForUpdates: Bool {
3549
get { updater.automaticallyChecksForUpdates }
3650
set { updater.automaticallyChecksForUpdates = newValue }
3751
}
3852
}
3953

54+
public protocol UpdateCheckerDelegate: AnyObject {
55+
func prepareForRelaunch(finish: @escaping () -> Void)
56+
}
57+
4058
class UpdaterDelegate: NSObject, SPUUpdaterDelegate {
59+
let shouldAutomaticallyCheckForUpdate: Bool
60+
weak var updateCheckerDelegate: UpdateCheckerDelegate?
61+
62+
init(shouldAutomaticallyCheckForUpdate: Bool) {
63+
self.shouldAutomaticallyCheckForUpdate = shouldAutomaticallyCheckForUpdate
64+
}
65+
66+
func updater(_ updater: SPUUpdater, mayPerform updateCheck: SPUUpdateCheck) throws {
67+
// Not sure how it works
68+
// if !shouldAutomaticallyCheckForUpdate, updateCheck == .updatesInBackground {
69+
// throw CancellationError()
70+
// }
71+
}
72+
73+
func updater(
74+
_ updater: SPUUpdater,
75+
shouldPostponeRelaunchForUpdate item: SUAppcastItem,
76+
untilInvokingBlock installHandler: @escaping () -> Void
77+
) -> Bool {
78+
if let updateCheckerDelegate {
79+
updateCheckerDelegate.prepareForRelaunch(finish: installHandler)
80+
return true
81+
}
82+
return false
83+
}
84+
85+
func updater(_ updater: SPUUpdater, willScheduleUpdateCheckAfterDelay delay: TimeInterval) {
86+
Logger.updateChecker.info("Will schedule update check after delay: \(delay)")
87+
}
88+
89+
func updaterWillNotScheduleUpdateCheck(_ updater: SPUUpdater) {
90+
Logger.updateChecker.info("Will not schedule update check")
91+
}
92+
4193
func allowedChannels(for updater: SPUUpdater) -> Set<String> {
4294
if UserDefaults.shared.value(for: \.installBetaBuilds) {
4395
Set(["beta"])

ExtensionService/AppDelegate.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
2121
let service = Service.shared
2222
var statusBarItem: NSStatusItem!
2323
var xpcController: XPCController?
24-
let updateChecker =
25-
UpdateChecker(
26-
hostBundle: locateHostBundleURL(url: Bundle.main.bundleURL)
27-
.flatMap(Bundle.init(url:))
28-
)
24+
let updateChecker = UpdateChecker(
25+
hostBundle: locateHostBundleURL(url: Bundle.main.bundleURL)
26+
.flatMap(Bundle.init(url:)),
27+
shouldAutomaticallyCheckForUpdate: true
28+
)
2929

3030
func applicationDidFinishLaunching(_: Notification) {
3131
if ProcessInfo.processInfo.environment["IS_UNIT_TEST"] == "YES" { return }
3232
_ = XcodeInspector.shared
33+
updateChecker.updateCheckerDelegate = self
3334
service.start()
3435
AXIsProcessTrustedWithOptions([
3536
kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: true,
@@ -138,6 +139,15 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
138139
}
139140
}
140141

142+
extension AppDelegate: UpdateCheckerDelegate {
143+
func prepareForRelaunch(finish: @escaping () -> Void) {
144+
Task {
145+
await service.prepareForExit()
146+
finish()
147+
}
148+
}
149+
}
150+
141151
extension NSRunningApplication {
142152
var isUserOfService: Bool {
143153
[

Pro

Submodule Pro updated from b915eb2 to d58fa18

Tool/Sources/CodeiumService/CodeiumExtension.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ import Logger
55
import Preferences
66
import Workspace
77

8+
@globalActor public enum CodeiumActor {
9+
public actor TheActor {}
10+
public static let shared = TheActor()
11+
}
12+
813
public final class CodeiumExtension: BuiltinExtension {
914
public var suggestionServiceId: Preferences.BuiltInSuggestionFeatureProvider { .codeium }
1015

@@ -119,7 +124,7 @@ final class ServiceLocator {
119124
guard let workspace = workspacePool.workspaces[workspace.workspaceURL],
120125
let plugin = workspace.plugin(for: CodeiumWorkspacePlugin.self)
121126
else { return nil }
122-
return plugin.codeiumService
127+
return await plugin.codeiumService
123128
}
124129
}
125130

Tool/Sources/CodeiumService/CodeiumService.swift

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public class CodeiumService {
4848
var cancellationCounter: UInt64 = 0
4949
let openedDocumentPool = OpenedDocumentPool()
5050
let onServiceLaunched: () -> Void
51+
let onServiceTerminated: () -> Void
5152

5253
let languageServerURL: URL
5354
let supportURL: URL
@@ -63,13 +64,19 @@ public class CodeiumService {
6364
projectRootURL = URL(fileURLWithPath: "/")
6465
server = designatedServer
6566
onServiceLaunched = {}
67+
onServiceTerminated = {}
6668
languageServerURL = URL(fileURLWithPath: "/")
6769
supportURL = URL(fileURLWithPath: "/")
6870
}
6971

70-
public init(projectRootURL: URL, onServiceLaunched: @escaping () -> Void) throws {
72+
public init(
73+
projectRootURL: URL,
74+
onServiceLaunched: @escaping () -> Void,
75+
onServiceTerminated: @escaping () -> Void
76+
) throws {
7177
self.projectRootURL = projectRootURL
7278
self.onServiceLaunched = onServiceLaunched
79+
self.onServiceTerminated = onServiceTerminated
7380
let urls = try CodeiumService.createFoldersIfNeeded()
7481
languageServerURL = urls.executableURL.appendingPathComponent("language_server")
7582
supportURL = urls.supportURL
@@ -117,6 +124,7 @@ public class CodeiumService {
117124
self?.heartbeatTask?.cancel()
118125
self?.requestCounter = 0
119126
self?.cancellationCounter = 0
127+
self?.onServiceTerminated()
120128
Logger.codeium.info("Language server is terminated, will be restarted when needed.")
121129
}
122130

@@ -186,7 +194,7 @@ extension CodeiumService {
186194
throw E()
187195
}
188196
var ideVersion = await XcodeInspector.shared.safe.latestActiveXcode?.version
189-
?? fallbackXcodeVersion
197+
?? fallbackXcodeVersion
190198
let versionNumberSegmentCount = ideVersion.split(separator: ".").count
191199
if versionNumberSegmentCount == 2 {
192200
ideVersion += ".0"
@@ -237,8 +245,8 @@ extension CodeiumService: CodeiumSuggestionServiceType {
237245
let relativePath = getRelativePath(of: fileURL)
238246

239247
let task = Task {
240-
let request = await CodeiumRequest.GetCompletion(requestBody: .init(
241-
metadata: try getMetadata(),
248+
let request = try await CodeiumRequest.GetCompletion(requestBody: .init(
249+
metadata: getMetadata(),
242250
document: .init(
243251
absolute_path: fileURL.path,
244252
relative_path: relativePath,
@@ -266,7 +274,7 @@ extension CodeiumService: CodeiumSuggestionServiceType {
266274

267275
try Task.checkCancellation()
268276

269-
let result = try await (try await setupServerIfNeeded()).sendRequest(request)
277+
let result = try await (await setupServerIfNeeded()).sendRequest(request)
270278

271279
try Task.checkCancellation()
272280

0 commit comments

Comments
 (0)