Skip to content

Commit bed6b1a

Browse files
committed
Support installing and removing GitHub Copilot language server
1 parent 1a1e770 commit bed6b1a

2 files changed

Lines changed: 92 additions & 2 deletions

File tree

Core/Sources/GitHubCopilotService/GitHubCopilotInstallationManager.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ public struct GitHubCopilotInstallationManager {
5858
continuation.yield(.downloading)
5959
let urls = try GitHubCopilotBaseService.createFoldersIfNeeded()
6060
let executable = Bundle.main.bundleURL.appendingPathComponent("Contents/Applications/CopilotForXcodeExtensionService.app/Contents/Resources/copilot")
61-
print(executable)
6261
guard FileManager.default.fileExists(atPath: executable.path) else {
6362
throw Error.failedToFindLanguageServer
6463
}

Core/Sources/HostApp/AccountSettings/CopilotView.swift

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,69 @@ struct CopilotView: View {
1616

1717
init() {}
1818
}
19+
20+
class ViewModel: ObservableObject {
21+
let installationManager = GitHubCopilotInstallationManager()
22+
23+
@Published var installationStatus: GitHubCopilotInstallationManager.InstallationStatus
24+
@Published var installationStep: GitHubCopilotInstallationManager.InstallationStep?
25+
26+
init() {
27+
installationStatus = installationManager.checkInstallation()
28+
}
29+
30+
init(
31+
installationStatus: GitHubCopilotInstallationManager.InstallationStatus,
32+
installationStep: GitHubCopilotInstallationManager.InstallationStep?
33+
) {
34+
assert(isPreview)
35+
self.installationStatus = installationStatus
36+
self.installationStep = installationStep
37+
}
38+
39+
func refreshInstallationStatus() {
40+
Task { @MainActor in
41+
installationStatus = installationManager.checkInstallation()
42+
}
43+
}
44+
45+
func install() async throws {
46+
defer { refreshInstallationStatus() }
47+
do {
48+
for try await step in installationManager.installLatestVersion() {
49+
Task { @MainActor in
50+
self.installationStep = step
51+
}
52+
}
53+
Task {
54+
try await Task.sleep(nanoseconds: 1_000_000_000)
55+
Task { @MainActor in
56+
self.installationStep = nil
57+
}
58+
}
59+
} catch {
60+
Task { @MainActor in
61+
installationStep = nil
62+
}
63+
throw error
64+
}
65+
}
66+
67+
func uninstall() {
68+
Task {
69+
defer { refreshInstallationStatus() }
70+
try await installationManager.uninstall()
71+
Task { @MainActor in
72+
CopilotView.copilotAuthService = nil
73+
}
74+
}
75+
}
76+
}
1977

2078
@Environment(\.openURL) var openURL
2179
@Environment(\.toast) var toast
2280
@StateObject var settings = Settings()
81+
@StateObject var viewModel = ViewModel()
2382

2483
@State var status: GitHubCopilotAccountStatus?
2584
@State var userCode: String?
@@ -33,6 +92,30 @@ struct CopilotView: View {
3392
Self.copilotAuthService = service
3493
return service
3594
}
95+
96+
var installButton: some View {
97+
Button(action: {
98+
Task {
99+
do {
100+
try await viewModel.install()
101+
} catch {
102+
toast(Text(error.localizedDescription), .error)
103+
}
104+
}
105+
}) {
106+
Text("Install")
107+
}
108+
.disabled(viewModel.installationStep != nil)
109+
}
110+
111+
var uninstallButton: some View {
112+
Button(action: {
113+
viewModel.uninstall()
114+
}) {
115+
Text("Uninstall")
116+
}
117+
.disabled(viewModel.installationStep != nil)
118+
}
36119

37120
var body: some View {
38121
HStack {
@@ -66,7 +149,15 @@ struct CopilotView: View {
66149
.foregroundColor(.secondary)
67150

68151
VStack(alignment: .leading) {
69-
Text("Language Server Version: \(version ?? "Loading..")")
152+
HStack {
153+
Text("Language Server Version: \(version ?? "Loading..")")
154+
switch viewModel.installationStatus {
155+
case .notInstalled:
156+
installButton
157+
case .installed:
158+
uninstallButton
159+
}
160+
}
70161
Text("Status: \(status?.description ?? "Loading..")")
71162

72163
HStack(alignment: .center) {

0 commit comments

Comments
 (0)