Skip to content

Commit a8d1ce6

Browse files
committed
Even more cleanup & fixes
1 parent c9c07ab commit a8d1ce6

File tree

10 files changed

+387
-272
lines changed

10 files changed

+387
-272
lines changed

CodeEdit/Features/LSP/Registry/InstallationMethod.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,14 @@ enum InstallationMethod: Equatable {
5353

5454
func packageManager(installPath: URL) -> PackageManagerProtocol? {
5555
switch packageManagerType {
56-
// case .npm:
57-
// return NPMPackageManager(installationDirectory: installPath)
56+
case .npm:
57+
return NPMPackageManager(installationDirectory: installPath)
5858
// case .cargo:
5959
// return CargoPackageManager(installationDirectory: installPath)
6060
// case .pip:
6161
// return PipPackageManager(installationDirectory: installPath)
62-
// case .golang:
63-
// return GolangPackageManager(installationDirectory: installPath)
62+
case .golang:
63+
return GolangPackageManager(installationDirectory: installPath)
6464
case .github, .sourceBuild:
6565
return GithubPackageManager(installationDirectory: installPath)
6666
case .nuget, .opam, .gem, .composer:

CodeEdit/Features/LSP/Registry/PackageManagerError.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,42 @@
55
// Created by Abe Malla on 5/12/25.
66
//
77

8-
enum PackageManagerError: Error {
8+
import Foundation
9+
10+
enum PackageManagerError: Error, LocalizedError {
911
case unknown
1012
case packageManagerNotInstalled
1113
case initializationFailed(String)
1214
case installationFailed(String)
1315
case invalidConfiguration
16+
17+
var errorDescription: String? {
18+
switch self {
19+
case .unknown:
20+
"Unknown error occurred"
21+
case .packageManagerNotInstalled:
22+
"The required package manager is not installed."
23+
case .initializationFailed:
24+
"Installation directory initialization failed."
25+
case .installationFailed:
26+
"Package installation failed."
27+
case .invalidConfiguration:
28+
"The package registry contained an invalid installation configuration."
29+
}
30+
}
31+
32+
var failureReason: String? {
33+
switch self {
34+
case .unknown:
35+
nil
36+
case .packageManagerNotInstalled:
37+
nil
38+
case .initializationFailed(let string):
39+
string
40+
case .installationFailed(let string):
41+
string
42+
case .invalidConfiguration:
43+
nil
44+
}
45+
}
1446
}

CodeEdit/Features/LSP/Registry/PackageManagers/Install/PackageManagerInstallOperation.swift

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,17 @@ import Combine
1010

1111
@MainActor
1212
final class PackageManagerInstallOperation: ObservableObject, Identifiable {
13-
struct OutputItem: Identifiable {
14-
var id: UUID = UUID()
15-
var contents: String
13+
struct OutputItem: Identifiable, Equatable {
14+
let id: UUID = UUID()
15+
let isStepDivider: Bool
16+
let outputIdx: Int?
17+
let contents: String
18+
19+
init(outputIdx: Int? = nil, isStepDivider: Bool = false, contents: String) {
20+
self.isStepDivider = isStepDivider
21+
self.outputIdx = outputIdx
22+
self.contents = contents
23+
}
1624
}
1725

1826
nonisolated var id: String { package.name }
@@ -35,6 +43,7 @@ final class PackageManagerInstallOperation: ObservableObject, Identifiable {
3543
private let shellClient: ShellClient = .live()
3644
private var operationTask: Task<Void, Error>?
3745
private var confirmationContinuation: CheckedContinuation<Void, Never>?
46+
private var outputIdx = 0
3847

3948
init(package: RegistryItem, steps: [PackageManagerInstallStep]) {
4049
self.package = package
@@ -87,11 +96,19 @@ final class PackageManagerInstallOperation: ObservableObject, Identifiable {
8796
progress.addChild(model.progress, withPendingUnitCount: 1)
8897

8998
try Task.checkCancellation()
99+
accumulatedOutput.append(OutputItem(isStepDivider: true, contents: "Step \(currentStepIdx + 1): \(task.name)"))
100+
90101
await withTaskGroup(of: Void.self) { group in
91102
group.addTask {
92-
for await line in model.outputStream {
103+
for await outputItem in model.outputStream {
93104
await MainActor.run {
94-
self.accumulatedOutput.append(OutputItem(contents: line))
105+
switch outputItem {
106+
case .status(let string):
107+
self.outputIdx += 1
108+
self.accumulatedOutput.append(OutputItem(outputIdx: self.outputIdx, contents: string))
109+
case .output(let string):
110+
self.accumulatedOutput.append(OutputItem(contents: string))
111+
}
95112
}
96113
}
97114
}
@@ -113,6 +130,7 @@ final class PackageManagerInstallOperation: ObservableObject, Identifiable {
113130

114131
try Task.checkCancellation()
115132
if let error {
133+
progress.cancel()
116134
throw error
117135
}
118136
try await runNext()

CodeEdit/Features/LSP/Registry/PackageManagers/Install/PackageManagerProgressModel.swift

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,25 @@ import Combine
1010

1111
@MainActor
1212
final class PackageManagerProgressModel: ObservableObject {
13-
let outputStream: AsyncStream<String>
13+
enum OutputItem {
14+
case status(String)
15+
case output(String)
16+
}
17+
18+
let outputStream: AsyncStream<OutputItem>
1419
@Published var progress: Progress
1520

1621
private let shellClient: ShellClient
17-
private let outputContinuation: AsyncStream<String>.Continuation
22+
private let outputContinuation: AsyncStream<OutputItem>.Continuation
1823

1924
init(shellClient: ShellClient) {
2025
self.shellClient = shellClient
2126
self.progress = Progress(totalUnitCount: 1)
22-
(outputStream, outputContinuation) = AsyncStream<String>.makeStream()
27+
(outputStream, outputContinuation) = AsyncStream<OutputItem>.makeStream()
2328
}
2429

2530
func status(_ string: String) {
26-
outputContinuation.yield(string)
31+
outputContinuation.yield(.status(string))
2732
}
2833

2934
/// Creates the directory for the language server to be installed in
@@ -43,17 +48,19 @@ final class PackageManagerProgressModel: ObservableObject {
4348
}
4449

4550
/// Executes commands in the specified directory
51+
@discardableResult
4652
func executeInDirectory(in packagePath: String, _ args: [String]) async throws -> [String] {
4753
return try await runCommand("cd \"\(packagePath)\" && \(args.joined(separator: " "))")
4854
}
4955

5056
/// Runs a shell command and returns output
57+
@discardableResult
5158
func runCommand(_ command: String) async throws -> [String] {
5259
var output: [String] = []
53-
status("Executing: \(command)")
60+
status("\(command)")
5461
for try await line in shellClient.runAsync(command) {
5562
output.append(line)
56-
outputContinuation.yield(line)
63+
outputContinuation.yield(.output(line))
5764
}
5865
return output
5966
}

CodeEdit/Features/LSP/Registry/PackageManagers/Sources/NPMPackageManager.swift

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ final class NPMPackageManager: PackageManagerProtocol {
2727
let packagePath = installationDirectory.appending(path: source.entryName)
2828
return [
2929
initialize(in: packagePath),
30-
runNpmInstall(source, in: installationDirectory),
31-
verifyInstallation(source, installDir: installationDirectory)
30+
runNpmInstall(source, installDir: packagePath),
31+
verifyInstallation(source, installDir: packagePath)
3232
]
3333

3434
}
@@ -91,7 +91,7 @@ final class NPMPackageManager: PackageManagerProtocol {
9191

9292
// MARK: - NPM Install
9393

94-
func runNpmInstall(_ source: PackageSource, in packagePath: URL) -> PackageManagerInstallStep {
94+
func runNpmInstall(_ source: PackageSource, installDir installationDirectory: URL) -> PackageManagerInstallStep {
9595
let qualifiedSourceName = "\(source.pkgName)@\(source.version)"
9696
let otherPackages = source.options["extraPackages"]?
9797
.split(separator: ",")
@@ -127,9 +127,12 @@ final class NPMPackageManager: PackageManagerProtocol {
127127
installArgs.append(extraPackage)
128128
}
129129

130-
_ = try await model.executeInDirectory(in: packagePath.path, installArgs)
130+
_ = try await model.executeInDirectory(
131+
in: installationDirectory.path(percentEncoded: false),
132+
installArgs
133+
)
131134
} catch {
132-
let nodeModulesPath = packagePath.appending(path: "node_modules").path
135+
let nodeModulesPath = installationDirectory.appending(path: "node_modules").path(percentEncoded: false)
133136
try? FileManager.default.removeItem(atPath: nodeModulesPath)
134137
throw error
135138
}
@@ -141,17 +144,15 @@ final class NPMPackageManager: PackageManagerProtocol {
141144
/// Verify the installation was successful
142145
private func verifyInstallation(
143146
_ source: PackageSource,
144-
installDir installationDirectory: URL
147+
installDir packagePath: URL
145148
) -> PackageManagerInstallStep {
146-
let folderName = source.entryName
147149
let package = source.pkgName
148150
let version = source.version
149151

150152
return PackageManagerInstallStep(
151153
name: "Verify Installation",
152154
confirmation: .none
153155
) { _ in
154-
let packagePath = installationDirectory.appending(path: folderName)
155156
let packageJsonPath = packagePath.appending(path: "package.json").path
156157

157158
// Verify package.json contains the installed package

0 commit comments

Comments
 (0)