Files
sourcekit-lsp/Sources/SourceKitLSP/Hooks.swift
T
Rintaro Ishizaki 4b2fa3193a Allow injection of a pre-initialized sourcekitd connection
Introduce `SourceKitDCore` as the protocol boundary between dylib
lifecycle management and the high-level `SourceKitD` API. Its single
lifecycle entry point, `initializeService(api:notificationCallback:)`,
receives the already-loaded `sourcekitd_api_functions_t` from
`SourceKitD.init(core:)`.

`SourceKitDCoreImpl` is the standard implementation: `init` opens the
dylib; `initializeService` registers any plugin paths, calls
`api.initialize()`, and wires the notification handler; `deinit` calls
`shutdown()` and closes the handle. Pre-initialized conformances
implement `initializeService` as a no-op.

Wire a `sourcekitdCoreInjector` hook through `Hooks` so an embedding
host can return a pre-initialized `SourceKitDCore` for a given toolchain
path, preventing `sourcekitd_initialize()` from being called a second
time.

Declare `SourceKitDCoreForPlugin` at its use sites so each call site
can express the exact deinit behavior it needs: `dlclose` for handles
acquired via `RTLD_NOLOAD`, and `leak` for externally-owned handles.
2026-05-07 09:58:47 -07:00

62 lines
2.5 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 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
//
//===----------------------------------------------------------------------===//
package import BuildServerIntegration
package import Foundation
@_spi(SourceKitLSP) package import LanguageServerProtocol
@_spi(SourceKitLSP) import LanguageServerProtocolExtensions
package import SemanticIndex
package import SourceKitD
import struct TSCBasic.AbsolutePath
import struct TSCBasic.RelativePath
/// Closures can be used to inspect or modify internal behavior in SourceKit-LSP.
public struct Hooks: Sendable {
package var indexHooks: IndexHooks
package var buildServerHooks: BuildServerHooks
/// A hook that will be executed before a request is handled.
///
/// This allows requests to be artificially delayed.
package var preHandleRequest: (@Sendable (any RequestType) async -> Void)?
/// Closure that is executed before a request is forwarded to clangd.
///
/// This allows tests to simulate a `clangd` process that's unresponsive.
package var preForwardRequestToClangd: (@Sendable (any RequestType) async -> Void)?
/// If set, called by `SwiftLanguageService` instead of `SourceKitD.getOrCreate` to obtain a
/// pre-initialized sourcekitd connection, avoiding double-initialization when running in-process.
/// The URL passed is the toolchain root (`.xctoolchain` bundle path).
package var sourcekitdCoreInjector: (@Sendable (URL) throws -> (any SourceKitDCore)?)?
public init() {
self.init(indexHooks: IndexHooks(), buildServerHooks: BuildServerHooks())
}
package init(
indexHooks: IndexHooks = IndexHooks(),
buildServerHooks: BuildServerHooks = BuildServerHooks(),
preHandleRequest: (@Sendable (any RequestType) async -> Void)? = nil,
preForwardRequestToClangd: (@Sendable (any RequestType) async -> Void)? = nil,
sourcekitdCoreInjector: (@Sendable (URL) throws -> (any SourceKitDCore)?)? = nil
) {
self.indexHooks = indexHooks
self.buildServerHooks = buildServerHooks
self.preHandleRequest = preHandleRequest
self.preForwardRequestToClangd = preForwardRequestToClangd
self.sourcekitdCoreInjector = sourcekitdCoreInjector
}
}