Skip to content

Commit 64fe439

Browse files
committed
Make DocumentationLanguageService the only module that imports DocCDocumentation
1 parent 1ca9780 commit 64fe439

File tree

11 files changed

+93
-75
lines changed

11 files changed

+93
-75
lines changed

Sources/DocCDocumentation/DoccDocumentationError.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,13 @@ package import LanguageServerProtocol
1515

1616
package enum DocCDocumentationError: LocalizedError {
1717
case unsupportedLanguage(Language)
18-
case noDocumentableSymbols
1918
case indexNotAvailable
2019
case symbolNotFound(String)
2120

2221
var errorDescription: String? {
2322
switch self {
2423
case .unsupportedLanguage(let language):
2524
return "Documentation preview is not available for \(language.description) files"
26-
case .noDocumentableSymbols:
27-
return "No documentable symbols were found in this Swift file"
2825
case .indexNotAvailable:
2926
return "The index is not availble to complete the request"
3027
case .symbolNotFound(let symbolName):

Sources/DocumentationLanguageService/DoccDocumentationHandler.swift

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,16 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#if canImport(DocCDocumentation)
1413
import BuildServerIntegration
1514
import DocCDocumentation
1615
import Foundation
1716
@preconcurrency import IndexStoreDB
1817
package import LanguageServerProtocol
1918
import Markdown
19+
import SKLogging
2020
import SKUtilities
21-
import SourceKitLSP
2221
import SemanticIndex
23-
import SKLogging
22+
import SourceKitLSP
2423

2524
extension DocumentationLanguageService {
2625
package func doccDocumentation(_ req: DoccDocumentationRequest) async throws -> DoccDocumentationResponse {
@@ -76,7 +75,7 @@ extension DocumentationLanguageService {
7675
moduleName: String?,
7776
catalogURL: URL?
7877
) async throws -> DoccDocumentationResponse {
79-
return try await workspace.doccDocumentationManager.renderDocCDocumentation(
78+
return try await documentationManager.renderDocCDocumentation(
8079
tutorialFile: snapshot.text,
8180
moduleName: moduleName,
8281
catalogURL: catalogURL
@@ -92,7 +91,7 @@ extension DocumentationLanguageService {
9291
guard let sourceKitLSPServer else {
9392
throw ResponseError.internalError("SourceKit-LSP is shutting down")
9493
}
95-
let documentationManager = workspace.doccDocumentationManager
94+
let documentationManager = documentationManager
9695
guard case .symbol(let symbolName) = MarkdownTitleFinder.find(parsing: snapshot.text) else {
9796
// This is an article that can be rendered on its own
9897
return try await documentationManager.renderDocCDocumentation(
@@ -171,7 +170,6 @@ extension DocumentationLanguageService {
171170
guard let sourceKitLSPServer else {
172171
throw ResponseError.internalError("SourceKit-LSP is shutting down")
173172
}
174-
let documentationManager = workspace.doccDocumentationManager
175173
let (symbolGraph, symbolUSR, overrideDocComments) = try await sourceKitLSPServer.primaryLanguageService(
176174
for: snapshot.uri,
177175
snapshot.language,
@@ -275,4 +273,3 @@ struct MarkdownTitleFinder: MarkupVisitor {
275273
return .plainText(heading.plainText)
276274
}
277275
}
278-
#endif

Sources/DocumentationLanguageService/DocumentationLanguageService.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import DocCDocumentation
1314
import Foundation
1415
package import IndexStoreDB
1516
package import LanguageServerProtocol
@@ -23,6 +24,8 @@ package actor DocumentationLanguageService: LanguageService, Sendable {
2324
/// The ``SourceKitLSPServer`` instance that created this `DocumentationLanguageService`.
2425
private(set) weak var sourceKitLSPServer: SourceKitLSPServer?
2526

27+
let documentationManager: DocCDocumentationManager
28+
2629
var documentManager: DocumentManager {
2730
get throws {
2831
guard let sourceKitLSPServer else {
@@ -34,6 +37,12 @@ package actor DocumentationLanguageService: LanguageService, Sendable {
3437

3538
package static var builtInCommands: [String] { [] }
3639

40+
package static var experimentalCapabilities: [String: LSPAny] {
41+
return [
42+
DoccDocumentationRequest.method: .dictionary(["version": .int(1)])
43+
]
44+
}
45+
3746
package init(
3847
sourceKitLSPServer: SourceKitLSPServer,
3948
toolchain: Toolchain,
@@ -42,6 +51,7 @@ package actor DocumentationLanguageService: LanguageService, Sendable {
4251
workspace: Workspace
4352
) async throws {
4453
self.sourceKitLSPServer = sourceKitLSPServer
54+
self.documentationManager = DocCDocumentationManager(buildServerManager: workspace.buildServerManager)
4555
}
4656

4757
func workspaceForDocument(uri: DocumentURI) async throws -> Workspace? {
@@ -109,6 +119,10 @@ package actor DocumentationLanguageService: LanguageService, Sendable {
109119
// The DocumentationLanguageService does not do anything with document events
110120
}
111121

122+
package func filesDidChange(_ events: [FileEvent]) async {
123+
await documentationManager.filesDidChange(events)
124+
}
125+
112126
package func documentUpdatedBuildSettings(_ uri: DocumentURI) async {
113127
// The DocumentationLanguageService does not do anything with document events
114128
}

Sources/SKTestSupport/SkipUnless.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import Foundation
14+
import InProcessClient
1415
import LanguageServerProtocol
1516
import LanguageServerProtocolExtensions
1617
import RegexBuilder
@@ -386,6 +387,41 @@ package actor SkipUnless {
386387
)
387388
}
388389
}
390+
391+
/// Check if SourceKit-LSP was compiled with docc support
392+
package static func doccSupported(
393+
file: StaticString = #filePath,
394+
line: UInt = #line
395+
) async throws {
396+
return try await shared.skipUnlessSupported(file: file, line: line) {
397+
let server = try await SourceKitLSPServer(
398+
client: LocalConnection(receiverName: "client"),
399+
toolchainRegistry: .forTesting,
400+
languageServerRegistry: .staticallyKnownServices,
401+
options: .testDefault(),
402+
hooks: Hooks()
403+
)
404+
let initializeResponse = try await withCheckedThrowingContinuation { continuation in
405+
let initializeRequest = InitializeRequest(
406+
processId: nil,
407+
rootPath: nil,
408+
rootURI: nil,
409+
capabilities: ClientCapabilities(),
410+
trace: .off,
411+
workspaceFolders: []
412+
)
413+
server.handle(initializeRequest, id: .number(0)) { result in
414+
continuation.resume(with: result)
415+
}
416+
}
417+
guard case .dictionary(let dict) = initializeResponse.capabilities.experimental,
418+
dict[DoccDocumentationRequest.method] != nil
419+
else {
420+
return .featureUnsupported(skipMessage: "docc not supported")
421+
}
422+
return .featureSupported
423+
}
424+
}
389425
}
390426

391427
// MARK: - Parsing Swift compiler version

Sources/SourceKitLSP/LanguageService.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ package protocol LanguageService: AnyObject, Sendable {
121121
/// Identifiers of the commands that this language service can handle.
122122
static var builtInCommands: [String] { get }
123123

124+
/// Experimental capabilities that should be reported to the client if this language service is enabled.
125+
static var experimentalCapabilities: [String: LSPAny] { get }
126+
124127
// MARK: - Lifetime
125128

126129
func initialize(_ initialize: InitializeRequest) async throws -> InitializeResult
@@ -160,6 +163,10 @@ package protocol LanguageService: AnyObject, Sendable {
160163
func willSaveDocument(_ notification: WillSaveTextDocumentNotification) async
161164
func didSaveDocument(_ notification: DidSaveTextDocumentNotification) async
162165

166+
/// Called when files are changed on disk and the editor sends a `workspace/didChangeWatchedFiles` notification to
167+
/// SourceKit-LSP.
168+
func filesDidChange(_ events: [FileEvent]) async
169+
163170
// MARK: - Build Server Integration
164171

165172
/// Sent when the build server has resolved build settings, such as for the initial build settings
@@ -310,3 +317,9 @@ package protocol LanguageService: AnyObject, Sendable {
310317
/// Crash the language server. Should be used for crash recovery testing only.
311318
func crash() async
312319
}
320+
321+
package extension LanguageService {
322+
static var experimentalCapabilities: [String: LSPAny] { [:] }
323+
324+
func filesDidChange(_ events: [FileEvent]) async {}
325+
}

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ package import ToolchainRegistry
2828
import struct TSCBasic.AbsolutePath
2929
import protocol TSCBasic.FileSystem
3030

31-
#if canImport(DocCDocumentation)
32-
import DocCDocumentation
33-
#endif
34-
3531
/// Disambiguate LanguageServerProtocol.Language and IndexstoreDB.Language
3632
package typealias Language = LanguageServerProtocol.Language
3733

@@ -1116,9 +1112,14 @@ extension SourceKitLSPServer {
11161112
GetReferenceDocumentRequest.method: .dictionary(["version": .int(1)]),
11171113
DidChangeActiveDocumentNotification.method: .dictionary(["version": .int(1)]),
11181114
]
1119-
#if canImport(DocCDocumentation)
1120-
experimentalCapabilities["textDocument/doccDocumentation"] = .dictionary(["version": .int(1)])
1121-
#endif
1115+
for (key, value) in languageServiceRegistry.languageServices.flatMap({ $0.type.experimentalCapabilities }) {
1116+
if let existingValue = experimentalCapabilities[key] {
1117+
logger.error(
1118+
"Conflicting experimental capabilities for \(key): \(existingValue.forLogging) vs \(value.forLogging)"
1119+
)
1120+
}
1121+
experimentalCapabilities[key] = value
1122+
}
11221123

11231124
return ServerCapabilities(
11241125
textDocumentSync: .options(
@@ -1520,6 +1521,10 @@ extension SourceKitLSPServer {
15201521
// (e.g. Package.swift doesn't have build settings but affects build
15211522
// settings). Inform the build server about all file changes.
15221523
await workspaces.concurrentForEach { await $0.filesDidChange(notification.changes) }
1524+
1525+
for languageService in languageServices.values.flatMap(\.self) {
1526+
await languageService.filesDidChange(notification.changes)
1527+
}
15231528
}
15241529

15251530
func setBackgroundIndexingPaused(_ request: SetOptionsRequest) async throws -> VoidResponse {

Sources/SourceKitLSP/Workspace.swift

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ import ToolchainRegistry
2626
import struct TSCBasic.AbsolutePath
2727
import struct TSCBasic.RelativePath
2828

29-
#if canImport(DocCDocumentation)
30-
package import DocCDocumentation
31-
#endif
32-
3329
/// Actor that caches realpaths for `sourceFilesWithSameRealpath`.
3430
fileprivate actor SourceFilesWithSameRealpathInferrer {
3531
private let buildServerManager: BuildServerManager
@@ -101,10 +97,6 @@ package final class Workspace: Sendable, BuildServerManagerDelegate {
10197
/// The build server manager to use for documents in this workspace.
10298
package let buildServerManager: BuildServerManager
10399

104-
#if canImport(DocCDocumentation)
105-
package let doccDocumentationManager: DocCDocumentationManager
106-
#endif
107-
108100
private let sourceFilesWithSameRealpathInferrer: SourceFilesWithSameRealpathInferrer
109101

110102
let options: SourceKitLSPOptions
@@ -153,9 +145,6 @@ package final class Workspace: Sendable, BuildServerManagerDelegate {
153145
self.options = options
154146
self._uncheckedIndex = ThreadSafeBox(initialValue: uncheckedIndex)
155147
self.buildServerManager = buildServerManager
156-
#if canImport(DocCDocumentation)
157-
self.doccDocumentationManager = DocCDocumentationManager(buildServerManager: buildServerManager)
158-
#endif
159148
self.sourceFilesWithSameRealpathInferrer = SourceFilesWithSameRealpathInferrer(
160149
buildServerManager: buildServerManager
161150
)
@@ -417,9 +406,6 @@ package final class Workspace: Sendable, BuildServerManagerDelegate {
417406

418407
// Notify all clients about the reported and inferred edits.
419408
await buildServerManager.filesDidChange(events)
420-
#if canImport(DocCDocumentation)
421-
await doccDocumentationManager.filesDidChange(events)
422-
#endif
423409

424410
async let updateSyntacticIndex: Void = await syntacticTestIndex.filesDidChange(events)
425411
async let updateSemanticIndex: Void? = await semanticIndexManager?.filesDidChange(events)

Sources/SwiftLanguageService/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
add_library(SwiftLanguageService STATIC
22
SemanticRefactoring.swift
3-
DoccDocumentation.swift
43
SwiftTestingScanner.swift
54
FoldingRange.swift
65
CMakeLists.txt

Sources/SwiftLanguageService/DoccDocumentation.swift

Lines changed: 0 additions & 31 deletions
This file was deleted.

Sources/SwiftLanguageService/SwiftLanguageService.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,10 @@ extension SwiftLanguageService {
802802
)
803803
}
804804

805+
package func doccDocumentation(_ req: DoccDocumentationRequest) async throws -> DoccDocumentationResponse {
806+
throw ResponseError.requestNotImplemented(DoccDocumentationRequest.self)
807+
}
808+
805809
package func documentColor(_ req: DocumentColorRequest) async throws -> [ColorInformation] {
806810
let snapshot = try self.documentManager.latestSnapshot(req.textDocument.uri)
807811

0 commit comments

Comments
 (0)