Skip to content

Commit 4f792e8

Browse files
committed
Register language services in a dynamic registry
1 parent c83061e commit 4f792e8

File tree

7 files changed

+65
-61
lines changed

7 files changed

+65
-61
lines changed

Sources/InProcessClient/InProcessSourceKitLSPClient.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public final class InProcessSourceKitLSPClient: Sendable {
6060
self.server = SourceKitLSPServer(
6161
client: serverToClientConnection,
6262
toolchainRegistry: toolchainRegistry,
63+
languageServerRegistry: LanguageServiceRegistry(),
6364
options: options,
6465
hooks: hooks,
6566
onExit: {

Sources/SKTestSupport/TestSourceKitLSPClient.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ package final class TestSourceKitLSPClient: MessageHandler, Sendable {
164164
server = SourceKitLSPServer(
165165
client: serverToClientConnection,
166166
toolchainRegistry: toolchainRegistry,
167+
languageServerRegistry: LanguageServiceRegistry(),
167168
options: options,
168169
hooks: hooks,
169170
onExit: {

Sources/SourceKitLSP/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ add_library(SourceKitLSP STATIC
66
Hooks.swift
77
IndexProgressManager.swift
88
IndexStoreDB+MainFilesProvider.swift
9-
LanguageServerType.swift
9+
LanguageServiceRegistry.swift
1010
LanguageService.swift
1111
LogMessageNotification+representingStructureUsingEmojiPrefixIfNecessary.swift
1212
MessageHandlingDependencyTracker.swift

Sources/SourceKitLSP/LanguageServerType.swift

Lines changed: 0 additions & 54 deletions
This file was deleted.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import IndexStoreDB
14+
import LanguageServerProtocol
15+
import SKLogging
16+
17+
/// Registry in which conformers to `LanguageService` can be registered to server semantic functionality for a set of
18+
/// languages.
19+
package struct LanguageServiceRegistry {
20+
private var byLanguage: [Language: LanguageService.Type] = [:]
21+
22+
package init() {
23+
self.register(ClangLanguageService.self, for: [.c, .cpp, .objective_c, .objective_cpp])
24+
self.register(SwiftLanguageService.self, for: [.swift])
25+
self.register(DocumentationLanguageService.self, for: [.markdown, .tutorial])
26+
}
27+
28+
private mutating func register(_ languageService: LanguageService.Type, for languages: [Language]) {
29+
for language in languages {
30+
if let existingLanguageService = byLanguage[language] {
31+
logger.fault(
32+
"Cannot register \(languageService) for \(language, privacy: .public) because \(existingLanguageService) is already registered"
33+
)
34+
continue
35+
}
36+
byLanguage[language] = languageService
37+
}
38+
}
39+
40+
func languageService(for language: Language) -> LanguageService.Type? {
41+
return byLanguage[language]
42+
}
43+
}

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ import DocCDocumentation
3535
/// Disambiguate LanguageServerProtocol.Language and IndexstoreDB.Language
3636
package typealias Language = LanguageServerProtocol.Language
3737

38+
struct LanguageServiceIdentifier: Hashable {
39+
private let identifier: String
40+
41+
init(type: LanguageService.Type) {
42+
self.identifier = String(reflecting: type)
43+
}
44+
}
45+
3846
/// The SourceKit-LSP server.
3947
///
4048
/// This is the client-facing language server implementation, providing indexing, multiple-toolchain
@@ -75,7 +83,9 @@ package actor SourceKitLSPServer {
7583

7684
package var capabilityRegistry: CapabilityRegistry?
7785

78-
var languageServices: [LanguageServerType: [LanguageService]] = [:]
86+
private let languageServiceRegistry: LanguageServiceRegistry
87+
88+
var languageServices: [LanguageServiceIdentifier: [LanguageService]] = [:]
7989

8090
package let documentManager = DocumentManager()
8191

@@ -160,11 +170,13 @@ package actor SourceKitLSPServer {
160170
package init(
161171
client: Connection,
162172
toolchainRegistry: ToolchainRegistry,
173+
languageServerRegistry: LanguageServiceRegistry,
163174
options: SourceKitLSPOptions,
164175
hooks: Hooks,
165176
onExit: @escaping () -> Void = {}
166177
) {
167178
self.toolchainRegistry = toolchainRegistry
179+
self.languageServiceRegistry = languageServerRegistry
168180
self._options = ThreadSafeBox(initialValue: options)
169181
self.hooks = hooks
170182
self.onExit = onExit
@@ -450,11 +462,11 @@ package actor SourceKitLSPServer {
450462
/// If a language service of type `serverType` that can handle `workspace` using the given toolchain has already been
451463
/// started, return it, otherwise return `nil`.
452464
private func existingLanguageService(
453-
_ serverType: LanguageServerType,
465+
_ serverType: LanguageService.Type,
454466
toolchain: Toolchain,
455467
workspace: Workspace
456468
) -> LanguageService? {
457-
for languageService in languageServices[serverType, default: []] {
469+
for languageService in languageServices[LanguageServiceIdentifier(type: serverType), default: []] {
458470
if languageService.canHandle(workspace: workspace, toolchain: toolchain) {
459471
return languageService
460472
}
@@ -467,7 +479,7 @@ package actor SourceKitLSPServer {
467479
_ language: Language,
468480
in workspace: Workspace
469481
) async -> LanguageService? {
470-
guard let serverType = LanguageServerType(language: language) else {
482+
guard let serverType = languageServiceRegistry.languageService(for: language) else {
471483
logger.error("Unable to infer language server type for language '\(language)'")
472484
return nil
473485
}
@@ -478,7 +490,7 @@ package actor SourceKitLSPServer {
478490

479491
// Start a new service.
480492
return await orLog("failed to start language service", level: .error) { [options = workspace.options, hooks] in
481-
let service = try await serverType.serverType.init(
493+
let service = try await serverType.init(
482494
sourceKitLSPServer: self,
483495
toolchain: toolchain,
484496
options: options,
@@ -538,7 +550,7 @@ package actor SourceKitLSPServer {
538550
return concurrentlyInitializedService
539551
}
540552

541-
languageServices[serverType, default: []].append(service)
553+
languageServices[LanguageServiceIdentifier(type: serverType), default: []].append(service)
542554
return service
543555
}
544556
}

Sources/sourcekit-lsp/SourceKitLSP.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ struct SourceKitLSP: AsyncParsableCommand {
294294
let server = SourceKitLSPServer(
295295
client: clientConnection,
296296
toolchainRegistry: ToolchainRegistry(installPath: Bundle.main.bundleURL),
297+
languageServerRegistry: LanguageServiceRegistry(),
297298
options: globalConfigurationOptions,
298299
hooks: Hooks(),
299300
onExit: {

0 commit comments

Comments
 (0)