Merge pull request #2266 from ahoppen/bsp-failed-to-initialize

If a BSP server fails to initialize, show the error message to the user
This commit is contained in:
Alex Hoppen
2025-08-31 08:22:56 +02:00
committed by GitHub
2 changed files with 57 additions and 9 deletions

View File

@@ -329,8 +329,10 @@ package actor BuildServerManager: QueueBasedMessageHandler {
/// preferred over `buildServerAdapter` because no messages must be sent to the build server before initialization
/// finishes.
private var buildServerAdapterAfterInitialized: BuildServerAdapter? {
get async {
_ = await initializeResult.value
get async throws {
guard await initializeResult.value != nil else {
throw ResponseError.unknown("Build server failed to initialize")
}
return buildServerAdapter
}
}
@@ -505,8 +507,9 @@ package actor BuildServerManager: QueueBasedMessageHandler {
logger.fault("If we have a connectionToBuildServer, we must have had a buildServerSpec")
return nil
}
let initializeResponse = await orLog("Initializing build server") {
try await buildServerAdapter.send(
let initializeResponse: InitializeBuildResponse?
do {
initializeResponse = try await buildServerAdapter.send(
InitializeBuildRequest(
displayName: "SourceKit-LSP",
version: "",
@@ -515,7 +518,19 @@ package actor BuildServerManager: QueueBasedMessageHandler {
capabilities: BuildClientCapabilities(languageIds: [.c, .cpp, .objective_c, .objective_cpp, .swift])
)
)
} catch {
initializeResponse = nil
let errorMessage: String
if let error = error as? ResponseError {
errorMessage = error.message
} else {
errorMessage = "\(error)"
}
connectionToClient.send(
ShowMessageNotification(type: .error, message: "Failed to initialize build server: \(errorMessage)")
)
}
if let initializeResponse, !(initializeResponse.sourceKitData?.sourceKitOptionsProvider ?? false),
case .external(let externalBuildServerAdapter) = buildServerAdapter
{
@@ -559,7 +574,7 @@ package actor BuildServerManager: QueueBasedMessageHandler {
package func shutdown() async {
// Clear any pending work done progresses from the build server.
self.workDoneProgressManagers.removeAll()
guard let buildServerAdapter = await self.buildServerAdapterAfterInitialized else {
guard let buildServerAdapter = try? await self.buildServerAdapterAfterInitialized else {
return
}
await orLog("Sending shutdown request to build server") {
@@ -898,7 +913,7 @@ package actor BuildServerManager: QueueBasedMessageHandler {
in target: BuildTargetIdentifier,
language: Language
) async throws -> FileBuildSettings? {
guard let buildServerAdapter = await buildServerAdapterAfterInitialized else {
guard let buildServerAdapter = try await buildServerAdapterAfterInitialized else {
return nil
}
let request = TextDocumentSourceKitOptionsRequest(
@@ -1158,7 +1173,7 @@ package actor BuildServerManager: QueueBasedMessageHandler {
}
private func buildTargets() async throws -> [BuildTargetIdentifier: BuildTargetInfo] {
guard let buildServerAdapter = await buildServerAdapterAfterInitialized else {
guard let buildServerAdapter = try await buildServerAdapterAfterInitialized else {
return [:]
}
@@ -1198,7 +1213,7 @@ package actor BuildServerManager: QueueBasedMessageHandler {
}
package func sourceFiles(in targets: Set<BuildTargetIdentifier>) async throws -> [SourcesItem] {
guard let buildServerAdapter = await buildServerAdapterAfterInitialized, !targets.isEmpty else {
guard let buildServerAdapter = try await buildServerAdapterAfterInitialized, !targets.isEmpty else {
return []
}
@@ -1414,7 +1429,7 @@ package actor BuildServerManager: QueueBasedMessageHandler {
// MARK: Informing BuildSererManager about changes
package func filesDidChange(_ events: [FileEvent]) async {
if let buildServerAdapter = await buildServerAdapterAfterInitialized {
if let buildServerAdapter = try? await buildServerAdapterAfterInitialized {
await buildServerAdapter.send(OnWatchedFilesDidChangeNotification(changes: events))
}

View File

@@ -647,4 +647,37 @@ final class ExternalBuildServerTests: XCTestCase {
}
try await fulfillmentOfOrThrow(preparationFinished)
}
func testBuildServerFailsToInitialize() async throws {
actor BuildServer: CustomBuildServer {
let inProgressRequestsTracker = CustomBuildServerInProgressRequestTracker()
init(projectRoot: URL, connectionToSourceKitLSP: any Connection) {}
func initializeBuildRequest(_ request: InitializeBuildRequest) async throws -> InitializeBuildResponse {
throw ResponseError.unknown("Initialization failed with bad error")
}
func buildTargetSourcesRequest(_ request: BuildTargetSourcesRequest) async throws -> BuildTargetSourcesResponse {
throw ResponseError.unknown("Not expected to get called")
}
func textDocumentSourceKitOptionsRequest(
_ request: TextDocumentSourceKitOptionsRequest
) async throws -> TextDocumentSourceKitOptionsResponse? {
throw ResponseError.unknown("Not expected to get called")
}
}
let project = try await CustomBuildServerTestProject(
files: [
"Test.swift": """
func 1⃣myTestFunc() {}
"""
],
buildServer: BuildServer.self
)
let message = try await project.testClient.nextNotification(ofType: ShowMessageNotification.self)
assertContains(message.message, "Initialization failed with bad error")
}
}