Skip to content

Start migration of the communication between SourceKit-LSP and build systems to happen via the Build Server Protocol (BSP) #1649

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ let package = Package(
dependencies: [
"CAtomics",
"LanguageServerProtocol",
"LanguageServerProtocolJSONRPC",
"SKLogging",
"SwiftExtensions",
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
Expand Down
41 changes: 0 additions & 41 deletions Sources/BuildServerProtocol/BuildTargets.swift
Original file line number Diff line number Diff line change
Expand Up @@ -211,44 +211,3 @@ public struct OutputsItem: Codable, Hashable, Sendable {
/// The output paths for sources that belong to this build target.
public var outputPaths: [URI]
}

/// The build target changed notification is sent from the server to the client
/// to signal a change in a build target. The server communicates during the
/// initialize handshake whether this method is supported or not.
public struct BuildTargetsChangedNotification: NotificationType {
public static let method: String = "buildTarget/didChange"

public var changes: [BuildTargetEvent]

public init(changes: [BuildTargetEvent]) {
self.changes = changes
}
}

public struct BuildTargetEvent: Codable, Hashable, Sendable {
/// The identifier for the changed build target.
public var target: BuildTargetIdentifier

/// The kind of change for this build target.
public var kind: BuildTargetEventKind?

/// Any additional metadata about what information changed.
public var data: LSPAny?

public init(target: BuildTargetIdentifier, kind: BuildTargetEventKind?, data: LSPAny?) {
self.target = target
self.kind = kind
self.data = data
}
}

public enum BuildTargetEventKind: Int, Codable, Hashable, Sendable {
/// The build target is new.
case created = 1

/// The build target has changed.
case changed = 2

/// The build target has been deleted.
case deleted = 3
}
3 changes: 3 additions & 0 deletions Sources/BuildServerProtocol/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
add_library(BuildServerProtocol STATIC
BuildTargets.swift
DidChangeBuildTargetNotification.swift
DidChangeWatchedFilesNotification.swift
FileOptions.swift
InitializeBuild.swift
InverseSourcesRequest.swift
Messages.swift
RegisterForChangeNotifications.swift
ShutdownBuild.swift)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import LanguageServerProtocol

/// The build target changed notification is sent from the server to the client
/// to signal a change in a build target. The server communicates during the
/// initialize handshake whether this method is supported or not.
public struct DidChangeBuildTargetNotification: NotificationType, Equatable {
public static let method: String = "buildTarget/didChange"

/// **(BSP Extension)**
/// `changes` can be `nil` to indicate that all targets might have changed.
public var changes: [BuildTargetEvent]?

public init(changes: [BuildTargetEvent]?) {
self.changes = changes
}
}

public struct BuildTargetEvent: Codable, Hashable, Sendable {
/// The identifier for the changed build target.
public var target: BuildTargetIdentifier

/// The kind of change for this build target.
public var kind: BuildTargetEventKind?

/// Kind of data to expect in the `data` field. If this field is not set, the kind of data is not specified.
public var dataKind: String?

/// Any additional metadata about what information changed.
public var data: LSPAny?

public init(target: BuildTargetIdentifier, kind: BuildTargetEventKind?, dataKind: String?, data: LSPAny?) {
self.target = target
self.kind = kind
self.dataKind = dataKind
self.data = data
}
}

public enum BuildTargetEventKind: Int, Codable, Hashable, Sendable {
/// The build target is new.
case created = 1

/// The build target has changed.
case changed = 2

/// The build target has been deleted.
case deleted = 3
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import LanguageServerProtocol

/// Notification sent from SourceKit-LSP to the build system to indicate that files within the project have been modified.
public typealias DidChangeWatchedFilesNotification = LanguageServerProtocol.DidChangeWatchedFilesNotification
45 changes: 45 additions & 0 deletions Sources/BuildServerProtocol/InverseSourcesRequest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import LanguageServerProtocol

public struct TextDocumentIdentifier: Codable, Sendable, Hashable {
/// The text document's URI.
public var uri: URI

public init(uri: URI) {
self.uri = uri
}
}

/// The inverse sources request is sent from the client to the server to query for the list of build targets containing
/// a text document. The server communicates during the initialize handshake whether this method is supported or not.
/// This request can be viewed as the inverse of buildTarget/sources, except it only works for text documents and not
/// directories.
public struct InverseSourcesRequest: RequestType, Hashable {
public static let method: String = "buildTarget/inverseSources"
public typealias Response = InverseSourcesResponse

public var textDocument: TextDocumentIdentifier

public init(textDocument: TextDocumentIdentifier) {
self.textDocument = textDocument
}
}

public struct InverseSourcesResponse: ResponseType, Hashable {
public var targets: [BuildTargetIdentifier]

public init(targets: [BuildTargetIdentifier]) {
self.targets = targets
}
}
5 changes: 3 additions & 2 deletions Sources/BuildServerProtocol/Messages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@
import LanguageServerProtocol

fileprivate let requestTypes: [_RequestType.Type] = [
BuildTargets.self,
BuildTargetOutputPaths.self,
BuildTargets.self,
BuildTargetSources.self,
InitializeBuild.self,
InverseSourcesRequest.self,
RegisterForChanges.self,
ShutdownBuild.self,
SourceKitOptions.self,
]

fileprivate let notificationTypes: [NotificationType.Type] = [
BuildTargetsChangedNotification.self,
DidChangeBuildTargetNotification.self,
ExitBuildNotification.self,
FileOptionsChangedNotification.self,
InitializedBuildNotification.self,
Expand Down
30 changes: 17 additions & 13 deletions Sources/BuildSystemIntegration/BuildServerBuildSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ package actor BuildServerBuildSystem: MessageHandler {
self.delegate = delegate
}

package weak var messageHandler: BuiltInBuildSystemMessageHandler?

package func setMessageHandler(_ messageHandler: any BuiltInBuildSystemMessageHandler) {
self.messageHandler = messageHandler
}

/// The build settings that have been received from the build server.
private var buildSettings: [DocumentURI: FileBuildSettings] = [:]

Expand Down Expand Up @@ -194,7 +200,7 @@ package actor BuildServerBuildSystem: MessageHandler {
"""
)
bspMessageHandlingQueue.async {
if let params = params as? BuildTargetsChangedNotification {
if let params = params as? DidChangeBuildTargetNotification {
await self.handleBuildTargetsChanged(params)
} else if let params = params as? FileOptionsChangedNotification {
await self.handleFileOptionsChanged(params)
Expand All @@ -219,10 +225,8 @@ package actor BuildServerBuildSystem: MessageHandler {
reply(.failure(ResponseError.methodNotFound(R.method)))
}

func handleBuildTargetsChanged(
_ notification: BuildTargetsChangedNotification
) async {
await self.delegate?.buildTargetsChanged(notification.changes)
func handleBuildTargetsChanged(_ notification: DidChangeBuildTargetNotification) async {
await self.messageHandler?.sendNotificationToSourceKitLSP(notification)
}

func handleFileOptionsChanged(
Expand Down Expand Up @@ -254,7 +258,7 @@ private func readReponseDataKey(data: LSPAny?, key: String) -> String? {
return nil
}

extension BuildServerBuildSystem: BuildSystem {
extension BuildServerBuildSystem: BuiltInBuildSystem {
package nonisolated var supportsPreparation: Bool { false }

/// The build settings for the given file.
Expand All @@ -263,7 +267,7 @@ extension BuildServerBuildSystem: BuildSystem {
/// server yet or if no build settings are available for this file.
package func buildSettings(
for document: DocumentURI,
in target: ConfiguredTarget,
in target: BuildTargetIdentifier,
language: Language
) async -> FileBuildSettings? {
return buildSettings[document]
Expand All @@ -277,24 +281,24 @@ extension BuildServerBuildSystem: BuildSystem {
return nil
}

package func configuredTargets(for document: DocumentURI) async -> [ConfiguredTarget] {
return [ConfiguredTarget(targetID: "dummy", runDestinationID: "dummy")]
package func inverseSources(_ request: InverseSourcesRequest) -> InverseSourcesResponse {
return InverseSourcesResponse(targets: [BuildTargetIdentifier.dummy])
}

package func scheduleBuildGraphGeneration() {}

package func waitForUpToDateBuildGraph() async {}

package func topologicalSort(of targets: [ConfiguredTarget]) async -> [ConfiguredTarget]? {
package func topologicalSort(of targets: [BuildTargetIdentifier]) async -> [BuildTargetIdentifier]? {
return nil
}

package func targets(dependingOn targets: [ConfiguredTarget]) -> [ConfiguredTarget]? {
package func targets(dependingOn targets: [BuildTargetIdentifier]) -> [BuildTargetIdentifier]? {
return nil
}

package func prepare(
targets: [ConfiguredTarget],
targets: [BuildTargetIdentifier],
logMessageToIndexLog: @Sendable (_ taskID: IndexTaskID, _ message: String) -> Void
) async throws {
throw PrepareNotSupportedError()
Expand Down Expand Up @@ -326,7 +330,7 @@ extension BuildServerBuildSystem: BuildSystem {
}
}

package func filesDidChange(_ events: [FileEvent]) {}
package func didChangeWatchedFiles(notification: BuildServerProtocol.DidChangeWatchedFilesNotification) {}

package func fileHandlingCapability(for uri: DocumentURI) -> FileHandlingCapability {
guard
Expand Down
Loading