import BuiltinExtension import CopilotForXcodeKit import Foundation import Logger import Preferences import Workspace public final class CodeiumExtension: BuiltinExtension { public var suggestionServiceId: Preferences.BuiltInSuggestionFeatureProvider { .codeium } public let suggestionService: CodeiumSuggestionService? private var extensionUsage = ExtensionUsage( isSuggestionServiceInUse: false, isChatServiceInUse: false ) private var isLanguageServerInUse: Bool { extensionUsage.isSuggestionServiceInUse || extensionUsage.isChatServiceInUse } let workspacePool: WorkspacePool let serviceLocator: ServiceLocator public init(workspacePool: WorkspacePool) { self.workspacePool = workspacePool serviceLocator = .init(workspacePool: workspacePool) suggestionService = .init(serviceLocator: serviceLocator) } public func workspaceDidOpen(_: WorkspaceInfo) {} public func workspaceDidClose(_: WorkspaceInfo) {} public func workspace(_ workspace: WorkspaceInfo, didOpenDocumentAt documentURL: URL) { guard isLanguageServerInUse else { return } // check if file size is larger than 15MB, if so, return immediately if let attrs = try? FileManager.default .attributesOfItem(atPath: documentURL.path), let fileSize = attrs[FileAttributeKey.size] as? UInt64, fileSize > 15 * 1024 * 1024 { return } Task { do { let content = try String(contentsOf: documentURL, encoding: .utf8) guard let service = await serviceLocator.getService(from: workspace) else { return } try await service.notifyOpenTextDocument(fileURL: documentURL, content: content) } catch { Logger.gitHubCopilot.error(error.localizedDescription) } } } public func workspace(_ workspace: WorkspaceInfo, didSaveDocumentAt documentURL: URL) { // unimplemented } public func workspace(_ workspace: WorkspaceInfo, didCloseDocumentAt documentURL: URL) { guard isLanguageServerInUse else { return } Task { do { guard let service = await serviceLocator.getService(from: workspace) else { return } try await service.notifyCloseTextDocument(fileURL: documentURL) } catch { Logger.gitHubCopilot.error(error.localizedDescription) } } } public func workspace( _ workspace: WorkspaceInfo, didUpdateDocumentAt documentURL: URL, content: String? ) { guard isLanguageServerInUse else { return } // check if file size is larger than 15MB, if so, return immediately if let attrs = try? FileManager.default .attributesOfItem(atPath: documentURL.path), let fileSize = attrs[FileAttributeKey.size] as? UInt64, fileSize > 15 * 1024 * 1024 { return } Task { do { guard let content else { return } guard let service = await serviceLocator.getService(from: workspace) else { return } try await service.notifyOpenTextDocument(fileURL: documentURL, content: content) } catch { Logger.gitHubCopilot.error(error.localizedDescription) } } } public func extensionUsageDidChange(_ usage: ExtensionUsage) { extensionUsage = usage if !usage.isChatServiceInUse && !usage.isSuggestionServiceInUse { for workspace in workspacePool.workspaces.values { guard let plugin = workspace.plugin(for: CodeiumWorkspacePlugin.self) else { continue } plugin.terminate() } } } public func terminate() { for workspace in workspacePool.workspaces.values { guard let plugin = workspace.plugin(for: CodeiumWorkspacePlugin.self) else { continue } plugin.terminate() } } } final class ServiceLocator { let workspacePool: WorkspacePool init(workspacePool: WorkspacePool) { self.workspacePool = workspacePool } func getService(from workspace: WorkspaceInfo) async -> CodeiumService? { guard let workspace = workspacePool.workspaces[workspace.workspaceURL], let plugin = workspace.plugin(for: CodeiumWorkspacePlugin.self) else { return nil } return plugin.codeiumService } }