From 173784e8b7bbf93d766bc399e48d34e5c6d8f1fc Mon Sep 17 00:00:00 2001 From: loveucifer <134506987+loveucifer@users.noreply.github.com> Date: Mon, 5 Jan 2026 08:18:32 +0530 Subject: [PATCH 1/6] Closes #2211 Shut down language services when a workspace is closed - Added allLanguageServices property to Workspace to get all services it references - Added shutdownOrphanedLanguageServices to clean up services no longer in use - When workspace folders are removed, we now shut down their associated language services - This properly terminates clangd and other language server processes when workspaces close --- Sources/SourceKitLSP/SourceKitLSPServer.swift | 39 +++++++++++++++++++ Sources/SourceKitLSP/Workspace.swift | 5 +++ 2 files changed, 44 insertions(+) diff --git a/Sources/SourceKitLSP/SourceKitLSPServer.swift b/Sources/SourceKitLSP/SourceKitLSPServer.swift index 2883b0f3..fc7db680 100644 --- a/Sources/SourceKitLSP/SourceKitLSPServer.swift +++ b/Sources/SourceKitLSP/SourceKitLSPServer.swift @@ -1526,6 +1526,45 @@ extension SourceKitLSPServer { self.workspacesAndIsImplicit += newWorkspaces.map { (workspace: $0, isImplicit: false) } } }.value + + // Shut down any language services that are no longer referenced by any workspace. + await self.shutdownOrphanedLanguageServices() + } + + /// Shuts down any language services that are no longer referenced by any open workspace. + /// + /// This method gathers all language services that are currently referenced by open workspaces + /// and shuts down any language services that are not in that set. + private func shutdownOrphanedLanguageServices() async { + // Gather all language services referenced by open workspaces + var referencedServices: Set = [] + for workspace in workspaces { + for languageService in workspace.allLanguageServices { + referencedServices.insert(ObjectIdentifier(languageService)) + } + } + + // Find and remove orphaned language services + var orphanedServices: [any LanguageService] = [] + for (serviceType, services) in languageServices { + var remainingServices: [any LanguageService] = [] + for service in services { + if referencedServices.contains(ObjectIdentifier(service)) { + remainingServices.append(service) + } else { + orphanedServices.append(service) + } + } + if remainingServices.count != services.count { + languageServices[serviceType] = remainingServices.isEmpty ? nil : remainingServices + } + } + + // Shut down orphaned services + for service in orphanedServices { + logger.info("Shutting down orphaned language service: \(type(of: service))") + await service.shutdown() + } } func didChangeWatchedFiles(_ notification: DidChangeWatchedFilesNotification) async { diff --git a/Sources/SourceKitLSP/Workspace.swift b/Sources/SourceKitLSP/Workspace.swift index 7a1c83dd..9472277b 100644 --- a/Sources/SourceKitLSP/Workspace.swift +++ b/Sources/SourceKitLSP/Workspace.swift @@ -197,6 +197,11 @@ package final class Workspace: Sendable, BuildServerManagerDelegate { /// Language service for an open document, if available. private let languageServices: ThreadSafeBox<[DocumentURI: [any LanguageService]]> = ThreadSafeBox(initialValue: [:]) + /// All language services that are registered with this workspace. + var allLanguageServices: [any LanguageService] { + return languageServices.value.values.flatMap { $0 } + } + /// The task that constructs the `SemanticIndexManager`, which keeps track of whose file's index is up-to-date in the /// workspace and schedules indexing and preparation tasks for files with out-of-date index. /// From eeda46863914ca0501fe1edd6e9effd4d7e1bbf4 Mon Sep 17 00:00:00 2001 From: loveucifer <134506987+loveucifer@users.noreply.github.com> Date: Tue, 6 Jan 2026 17:50:24 +0530 Subject: [PATCH 2/6] test case additon --- Sources/SourceKitLSP/SourceKitLSPServer.swift | 13 +- Tests/SourceKitLSPTests/WorkspaceTests.swift | 154 ++++++++++++++++++ 2 files changed, 163 insertions(+), 4 deletions(-) diff --git a/Sources/SourceKitLSP/SourceKitLSPServer.swift b/Sources/SourceKitLSP/SourceKitLSPServer.swift index fc7db680..bbe2b540 100644 --- a/Sources/SourceKitLSP/SourceKitLSPServer.swift +++ b/Sources/SourceKitLSP/SourceKitLSPServer.swift @@ -1560,10 +1560,15 @@ extension SourceKitLSPServer { } } - // Shut down orphaned services - for service in orphanedServices { - logger.info("Shutting down orphaned language service: \(type(of: service))") - await service.shutdown() + // Shut down orphaned services in a background task to avoid blocking other requests. + + if !orphanedServices.isEmpty { + Task { + for service in orphanedServices { + logger.info("Shutting down orphaned language service: \(type(of: service))") + await service.shutdown() + } + } } } diff --git a/Tests/SourceKitLSPTests/WorkspaceTests.swift b/Tests/SourceKitLSPTests/WorkspaceTests.swift index 8b8efe59..a047d7fd 100644 --- a/Tests/SourceKitLSPTests/WorkspaceTests.swift +++ b/Tests/SourceKitLSPTests/WorkspaceTests.swift @@ -1386,6 +1386,160 @@ final class WorkspaceTests: SourceKitLSPTestCase { ) XCTAssertEqual(outputPaths.outputPaths.map { $0.suffix(13) }.sorted(), ["FileA.swift.o", "FileB.swift.o"]) } + + func testOrphanedClangLanguageServiceShutdown() async throws { + // test that when we remove a workspace, the ClangLanguageService for that workspace is shut down. + // verify this by checking that the language service is removed from the server's languageServices. + + let project = try await MultiFileTestProject( + files: [ + "WorkspaceA/compile_flags.txt": "", + "WorkspaceA/dummy.c": "", + "WorkspaceB/main.c": """ + int main() { return 0; } + """, + "WorkspaceB/compile_flags.txt": "", + ], + workspaces: { scratchDir in + return [ + WorkspaceFolder(uri: DocumentURI(scratchDir.appending(component: "WorkspaceA"))), + WorkspaceFolder(uri: DocumentURI(scratchDir.appending(component: "WorkspaceB"))), + ] + }, + usePullDiagnostics: false + ) + + // open a .c file in WorkspaceB to launch clangd + let (mainUri, _) = try project.openDocument("main.c") + + // send a request to ensure clangd is up and running + _ = try await project.testClient.send( + DocumentSymbolRequest(textDocument: TextDocumentIdentifier(mainUri)) + ) + + // get the language service for WorkspaceB before closing + let clangdServerBeforeClose = try await project.testClient.server.primaryLanguageService( + for: mainUri, + .c, + in: unwrap(project.testClient.server.workspaceForDocument(uri: mainUri)) + ) + + // close the document + project.testClient.send(DidCloseTextDocumentNotification(textDocument: TextDocumentIdentifier(mainUri))) + _ = try await project.testClient.send(SynchronizeRequest()) + + // remove WorkspaceB + let workspaceBUri = DocumentURI(project.scratchDirectory.appending(component: "WorkspaceB")) + project.testClient.send( + DidChangeWorkspaceFoldersNotification( + event: WorkspaceFoldersChangeEvent(removed: [WorkspaceFolder(uri: workspaceBUri)]) + ) + ) + _ = try await project.testClient.send(SynchronizeRequest()) + + + try await Task.sleep(for: .seconds(3)) + + + let workspaceAfterRemoval = await project.testClient.server.workspaceForDocument(uri: mainUri) + if let workspaceUri = workspaceAfterRemoval?.rootUri?.fileURL?.lastPathComponent { + XCTAssertFalse(workspaceUri == "WorkspaceB", "WorkspaceB should have been removed") + } + + // verify the language service is orphaned - opening a file in WorkspaceA should get a different language service + let (dummyUri, _) = try project.openDocument("dummy.c") + _ = try await project.testClient.send( + DocumentSymbolRequest(textDocument: TextDocumentIdentifier(dummyUri)) + ) + + let clangdServerForWorkspaceA = try await project.testClient.server.primaryLanguageService( + for: dummyUri, + .c, + in: unwrap(project.testClient.server.workspaceForDocument(uri: dummyUri)) + ) + + + XCTAssertFalse(clangdServerBeforeClose === clangdServerForWorkspaceA, "WorkspaceB's clangd should have been shut down and a new one created for WorkspaceA") + } + + func testOrphanedSwiftLanguageServiceShutdownAndRelaunch() async throws { + + try await SkipUnless.sourcekitdSupportsPlugin() + + let project = try await MultiFileTestProject( + files: [ + "WorkspaceA/Sources/LibA/LibA.swift": """ + public struct LibA { + public func 1️⃣foo() {} + public init() {} + } + """, + "WorkspaceA/Package.swift": """ + // swift-tools-version: 5.7 + import PackageDescription + let package = Package( + name: "LibA", + targets: [.target(name: "LibA")] + ) + """, + "WorkspaceB/Sources/LibB/LibB.swift": """ + public struct LibB { + public func bar() {} + public init() {} + } + """, + "WorkspaceB/Package.swift": """ + // swift-tools-version: 5.7 + import PackageDescription + let package = Package( + name: "LibB", + targets: [.target(name: "LibB")] + ) + """, + ], + workspaces: { scratchDir in + return [ + WorkspaceFolder(uri: DocumentURI(scratchDir.appending(component: "WorkspaceA"))), + WorkspaceFolder(uri: DocumentURI(scratchDir.appending(component: "WorkspaceB"))), + ] + } + ) + + + let (libBUri, _) = try project.openDocument("LibB.swift") + + + let initialHover = try await project.testClient.send( + HoverRequest(textDocument: TextDocumentIdentifier(libBUri), position: Position(line: 1, utf16index: 14)) + ) + XCTAssertNotNil(initialHover, "Should get hover response for LibB.swift") + + // close the document in WorkspaceB + project.testClient.send(DidCloseTextDocumentNotification(textDocument: TextDocumentIdentifier(libBUri))) + _ = try await project.testClient.send(SynchronizeRequest()) + + // remove WorkspaceB + let workspaceBUri = DocumentURI(project.scratchDirectory.appending(component: "WorkspaceB")) + project.testClient.send( + DidChangeWorkspaceFoldersNotification( + event: WorkspaceFoldersChangeEvent(removed: [WorkspaceFolder(uri: workspaceBUri)]) + ) + ) + _ = try await project.testClient.send(SynchronizeRequest()) + + // orphaned service to be shut down in the background + try await Task.sleep(for: .milliseconds(500)) + + // open a file in WorkspaceA + let (libAUri, positions) = try project.openDocument("LibA.swift") + + // verify that the language service in WorkspaceA still works correctly + let hover = try await project.testClient.send( + HoverRequest(textDocument: TextDocumentIdentifier(libAUri), position: positions["1️⃣"]) + ) + XCTAssertNotNil(hover, "Should still get hover response after removing WorkspaceB") + assertContains(hover?.contents.markupContent?.value ?? "", "foo") + } } private let defaultSDKArgs: String = { From 80d2c143cac7da4f76341435ec827090b6223e19 Mon Sep 17 00:00:00 2001 From: loveucifer <134506987+loveucifer@users.noreply.github.com> Date: Tue, 6 Jan 2026 21:43:25 +0530 Subject: [PATCH 3/6] Address PR feedback --- .../ClangLanguageService.swift | 4 ++- Tests/SourceKitLSPTests/WorkspaceTests.swift | 26 ++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Sources/ClangLanguageService/ClangLanguageService.swift b/Sources/ClangLanguageService/ClangLanguageService.swift index db12d357..b0246149 100644 --- a/Sources/ClangLanguageService/ClangLanguageService.swift +++ b/Sources/ClangLanguageService/ClangLanguageService.swift @@ -393,7 +393,9 @@ extension ClangLanguageService { guard let clangd else { return } // Give clangd 2 seconds to shut down by itself. If it doesn't shut down within that time, terminate it. try await withTimeout(.seconds(2)) { - _ = try await clangd.send(ShutdownRequest()) + let shutdownRequest = ShutdownRequest() + await self.sourceKitLSPServer?.hooks.preForwardRequestToClangd?(shutdownRequest) + _ = try await clangd.send(shutdownRequest) clangd.send(ExitNotification()) } } diff --git a/Tests/SourceKitLSPTests/WorkspaceTests.swift b/Tests/SourceKitLSPTests/WorkspaceTests.swift index a047d7fd..1b0832d3 100644 --- a/Tests/SourceKitLSPTests/WorkspaceTests.swift +++ b/Tests/SourceKitLSPTests/WorkspaceTests.swift @@ -1389,7 +1389,10 @@ final class WorkspaceTests: SourceKitLSPTestCase { func testOrphanedClangLanguageServiceShutdown() async throws { // test that when we remove a workspace, the ClangLanguageService for that workspace is shut down. - // verify this by checking that the language service is removed from the server's languageServices. + // verify this by checking that clangd receives a ShutdownRequest. + + let clangdReceivedShutdown = self.expectation(description: "clangd received shutdown request") + clangdReceivedShutdown.assertForOverFulfill = false let project = try await MultiFileTestProject( files: [ @@ -1406,6 +1409,11 @@ final class WorkspaceTests: SourceKitLSPTestCase { WorkspaceFolder(uri: DocumentURI(scratchDir.appending(component: "WorkspaceB"))), ] }, + hooks: Hooks(preForwardRequestToClangd: { request in + if request is ShutdownRequest { + clangdReceivedShutdown.fulfill() + } + }), usePullDiagnostics: false ) @@ -1426,7 +1434,6 @@ final class WorkspaceTests: SourceKitLSPTestCase { // close the document project.testClient.send(DidCloseTextDocumentNotification(textDocument: TextDocumentIdentifier(mainUri))) - _ = try await project.testClient.send(SynchronizeRequest()) // remove WorkspaceB let workspaceBUri = DocumentURI(project.scratchDirectory.appending(component: "WorkspaceB")) @@ -1436,15 +1443,15 @@ final class WorkspaceTests: SourceKitLSPTestCase { ) ) _ = try await project.testClient.send(SynchronizeRequest()) - - - try await Task.sleep(for: .seconds(3)) - + // wait for clangd to receive the shutdown request + try await fulfillmentOfOrThrow(clangdReceivedShutdown) let workspaceAfterRemoval = await project.testClient.server.workspaceForDocument(uri: mainUri) - if let workspaceUri = workspaceAfterRemoval?.rootUri?.fileURL?.lastPathComponent { - XCTAssertFalse(workspaceUri == "WorkspaceB", "WorkspaceB should have been removed") - } + XCTAssertNotEqual( + try XCTUnwrap(workspaceAfterRemoval?.rootUri?.fileURL?.lastPathComponent), + "WorkspaceB", + "WorkspaceB should have been removed" + ) // verify the language service is orphaned - opening a file in WorkspaceA should get a different language service let (dummyUri, _) = try project.openDocument("dummy.c") @@ -1516,7 +1523,6 @@ final class WorkspaceTests: SourceKitLSPTestCase { // close the document in WorkspaceB project.testClient.send(DidCloseTextDocumentNotification(textDocument: TextDocumentIdentifier(libBUri))) - _ = try await project.testClient.send(SynchronizeRequest()) // remove WorkspaceB let workspaceBUri = DocumentURI(project.scratchDirectory.appending(component: "WorkspaceB")) From 2019ab711ac56139ff8be46543b9ec0c80972b4c Mon Sep 17 00:00:00 2001 From: loveucifer <134506987+loveucifer@users.noreply.github.com> Date: Thu, 8 Jan 2026 04:58:27 +0530 Subject: [PATCH 4/6] mark SwiftLanguageService as immortal to skip shutdown --- Sources/SourceKitLSP/LanguageService.swift | 10 ++++ Sources/SourceKitLSP/SourceKitLSPServer.swift | 4 +- .../SwiftLanguageService/SwiftCommand.swift | 7 +++ Tests/SourceKitLSPTests/WorkspaceTests.swift | 57 ++++++++++++------- 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/Sources/SourceKitLSP/LanguageService.swift b/Sources/SourceKitLSP/LanguageService.swift index 2294fdec..76b1bb5b 100644 --- a/Sources/SourceKitLSP/LanguageService.swift +++ b/Sources/SourceKitLSP/LanguageService.swift @@ -126,6 +126,14 @@ package protocol LanguageService: AnyObject, Sendable { /// Experimental capabilities that should be reported to the client if this language service is enabled. static var experimentalCapabilities: [String: LSPAny] { get } + /// Whether this language service should be kept alive when its workspace is closed. + /// + /// When `true`, the language service will not be shut down even if all workspaces referencing it are closed. + /// This is useful for language services that use global state (like sourcekitd) where shutting down and + /// restarting would cause unnecessary overhead since the new instance will just reinitialize the same + /// global state. + static var isImmortal: Bool { get } + // MARK: - Lifetime func initialize(_ initialize: InitializeRequest) async throws -> InitializeResult @@ -351,6 +359,8 @@ package extension LanguageService { static var experimentalCapabilities: [String: LSPAny] { [:] } + static var isImmortal: Bool { false } + func clientInitialized(_ initialized: InitializedNotification) async {} func openOnDiskDocument(snapshot: DocumentSnapshot, buildSettings: FileBuildSettings) async throws { diff --git a/Sources/SourceKitLSP/SourceKitLSPServer.swift b/Sources/SourceKitLSP/SourceKitLSPServer.swift index bbe2b540..52604ca1 100644 --- a/Sources/SourceKitLSP/SourceKitLSPServer.swift +++ b/Sources/SourceKitLSP/SourceKitLSPServer.swift @@ -1544,12 +1544,12 @@ extension SourceKitLSPServer { } } - // Find and remove orphaned language services + // Find and remove orphaned language services, skipping immortal ones var orphanedServices: [any LanguageService] = [] for (serviceType, services) in languageServices { var remainingServices: [any LanguageService] = [] for service in services { - if referencedServices.contains(ObjectIdentifier(service)) { + if referencedServices.contains(ObjectIdentifier(service)) || type(of: service).isImmortal { remainingServices.append(service) } else { orphanedServices.append(service) diff --git a/Sources/SwiftLanguageService/SwiftCommand.swift b/Sources/SwiftLanguageService/SwiftCommand.swift index c6a51197..dd0dc52c 100644 --- a/Sources/SwiftLanguageService/SwiftCommand.swift +++ b/Sources/SwiftLanguageService/SwiftCommand.swift @@ -55,4 +55,11 @@ extension SwiftLanguageService { command.identifier } } + + /// `SwiftLanguageService` is immortal because sourcekitd uses global state. + /// + /// Since all instances of `SwiftLanguageService` share the same underlying sourcekitd process, + /// shutting down and restarting would cause unnecessary overhead as the new instance would + /// just reinitialize the same global state. Instead, we keep the service alive. + package static var isImmortal: Bool { true } } diff --git a/Tests/SourceKitLSPTests/WorkspaceTests.swift b/Tests/SourceKitLSPTests/WorkspaceTests.swift index 1b0832d3..41478099 100644 --- a/Tests/SourceKitLSPTests/WorkspaceTests.swift +++ b/Tests/SourceKitLSPTests/WorkspaceTests.swift @@ -1425,8 +1425,8 @@ final class WorkspaceTests: SourceKitLSPTestCase { DocumentSymbolRequest(textDocument: TextDocumentIdentifier(mainUri)) ) - // get the language service for WorkspaceB before closing - let clangdServerBeforeClose = try await project.testClient.server.primaryLanguageService( + // Get the language service for WorkspaceB before closing + let clangLanguageServiceBeforeClose = try await project.testClient.server.primaryLanguageService( for: mainUri, .c, in: unwrap(project.testClient.server.workspaceForDocument(uri: mainUri)) @@ -1459,18 +1459,19 @@ final class WorkspaceTests: SourceKitLSPTestCase { DocumentSymbolRequest(textDocument: TextDocumentIdentifier(dummyUri)) ) - let clangdServerForWorkspaceA = try await project.testClient.server.primaryLanguageService( + let clangLanguageServiceForWorkspaceA = try await project.testClient.server.primaryLanguageService( for: dummyUri, .c, in: unwrap(project.testClient.server.workspaceForDocument(uri: dummyUri)) ) - - XCTAssertFalse(clangdServerBeforeClose === clangdServerForWorkspaceA, "WorkspaceB's clangd should have been shut down and a new one created for WorkspaceA") + XCTAssertFalse( + clangLanguageServiceBeforeClose === clangLanguageServiceForWorkspaceA, + "WorkspaceB's ClangLanguageService should have been shut down and a new one created for WorkspaceA" + ) } - func testOrphanedSwiftLanguageServiceShutdownAndRelaunch() async throws { - + func testOrphanedSwiftLanguageServiceIsImmortal() async throws { try await SkipUnless.sourcekitdSupportsPlugin() let project = try await MultiFileTestProject( @@ -1491,7 +1492,7 @@ final class WorkspaceTests: SourceKitLSPTestCase { """, "WorkspaceB/Sources/LibB/LibB.swift": """ public struct LibB { - public func bar() {} + public func 2️⃣bar() {} public init() {} } """, @@ -1512,19 +1513,24 @@ final class WorkspaceTests: SourceKitLSPTestCase { } ) + let (libBUri, libBPositions) = try project.openDocument("LibB.swift") - let (libBUri, _) = try project.openDocument("LibB.swift") - - let initialHover = try await project.testClient.send( - HoverRequest(textDocument: TextDocumentIdentifier(libBUri), position: Position(line: 1, utf16index: 14)) + HoverRequest(textDocument: TextDocumentIdentifier(libBUri), position: libBPositions["2️⃣"]) ) XCTAssertNotNil(initialHover, "Should get hover response for LibB.swift") - // close the document in WorkspaceB + // Get the SwiftLanguageService before closing WorkspaceB + let swiftLanguageServiceBeforeClose = try await project.testClient.server.primaryLanguageService( + for: libBUri, + .swift, + in: unwrap(project.testClient.server.workspaceForDocument(uri: libBUri)) + ) + + // Close the document in WorkspaceB project.testClient.send(DidCloseTextDocumentNotification(textDocument: TextDocumentIdentifier(libBUri))) - // remove WorkspaceB + // Remove WorkspaceB let workspaceBUri = DocumentURI(project.scratchDirectory.appending(component: "WorkspaceB")) project.testClient.send( DidChangeWorkspaceFoldersNotification( @@ -1533,18 +1539,27 @@ final class WorkspaceTests: SourceKitLSPTestCase { ) _ = try await project.testClient.send(SynchronizeRequest()) - // orphaned service to be shut down in the background - try await Task.sleep(for: .milliseconds(500)) + // Open a file in WorkspaceA + let (libAUri, libAPositions) = try project.openDocument("LibA.swift") - // open a file in WorkspaceA - let (libAUri, positions) = try project.openDocument("LibA.swift") - - // verify that the language service in WorkspaceA still works correctly + // Verify that the language service in WorkspaceA still works correctly let hover = try await project.testClient.send( - HoverRequest(textDocument: TextDocumentIdentifier(libAUri), position: positions["1️⃣"]) + HoverRequest(textDocument: TextDocumentIdentifier(libAUri), position: libAPositions["1️⃣"]) ) XCTAssertNotNil(hover, "Should still get hover response after removing WorkspaceB") assertContains(hover?.contents.markupContent?.value ?? "", "foo") + + // Verify that the same SwiftLanguageService is reused (immortal, not shut down) + let swiftLanguageServiceForWorkspaceA = try await project.testClient.server.primaryLanguageService( + for: libAUri, + .swift, + in: unwrap(project.testClient.server.workspaceForDocument(uri: libAUri)) + ) + + XCTAssertTrue( + swiftLanguageServiceBeforeClose === swiftLanguageServiceForWorkspaceA, + "SwiftLanguageService should be immortal and reused across workspaces" + ) } } From 97ceb675eeb90b5640be63a40d252297abc69fce Mon Sep 17 00:00:00 2001 From: loveucifer <134506987+loveucifer@users.noreply.github.com> Date: Thu, 8 Jan 2026 13:18:17 +0530 Subject: [PATCH 5/6] tiny fix --- Tests/SourceKitLSPTests/WorkspaceTests.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/SourceKitLSPTests/WorkspaceTests.swift b/Tests/SourceKitLSPTests/WorkspaceTests.swift index 41478099..82d5730a 100644 --- a/Tests/SourceKitLSPTests/WorkspaceTests.swift +++ b/Tests/SourceKitLSPTests/WorkspaceTests.swift @@ -1413,8 +1413,7 @@ final class WorkspaceTests: SourceKitLSPTestCase { if request is ShutdownRequest { clangdReceivedShutdown.fulfill() } - }), - usePullDiagnostics: false + }) ) // open a .c file in WorkspaceB to launch clangd From 27b536d6124aa6512f8d3042998774a78f734d17 Mon Sep 17 00:00:00 2001 From: loveucifer <134506987+loveucifer@users.noreply.github.com> Date: Thu, 8 Jan 2026 18:36:50 +0530 Subject: [PATCH 6/6] format --- Sources/SourceKitLSP/SourceKitLSPServer.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/SourceKitLSP/SourceKitLSPServer.swift b/Sources/SourceKitLSP/SourceKitLSPServer.swift index 52604ca1..c92139f6 100644 --- a/Sources/SourceKitLSP/SourceKitLSPServer.swift +++ b/Sources/SourceKitLSP/SourceKitLSPServer.swift @@ -1561,7 +1561,7 @@ extension SourceKitLSPServer { } // Shut down orphaned services in a background task to avoid blocking other requests. - + if !orphanedServices.isEmpty { Task { for service in orphanedServices {