mirror of
https://github.com/apple/sourcekit-lsp.git
synced 2026-03-02 18:23:24 +01:00
108 lines
4.0 KiB
Swift
108 lines
4.0 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2022 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 Foundation
|
|
import SourceKitD
|
|
import LanguageServerProtocol
|
|
import LSPLogging
|
|
import SKSupport
|
|
|
|
struct InterfaceInfo {
|
|
var contents: String
|
|
}
|
|
|
|
extension SwiftLanguageServer {
|
|
public func openInterface(_ request: OpenInterfaceRequest) async throws -> InterfaceDetails? {
|
|
let uri = request.textDocument.uri
|
|
let moduleName = request.moduleName
|
|
let name = request.name
|
|
let symbol = request.symbolUSR
|
|
let interfaceFilePath = self.generatedInterfacesPath.appendingPathComponent("\(name).swiftinterface")
|
|
let interfaceDocURI = DocumentURI(interfaceFilePath)
|
|
// has interface already been generated
|
|
if let snapshot = self.documentManager.latestSnapshot(interfaceDocURI) {
|
|
return await self.interfaceDetails(request: request, uri: interfaceDocURI, snapshot: snapshot, symbol: symbol)
|
|
} else {
|
|
// generate interface
|
|
let interfaceInfo = try await self.openInterface(request: request, uri: uri, name: moduleName, interfaceURI: interfaceDocURI)
|
|
do {
|
|
// write to file
|
|
try interfaceInfo.contents.write(to: interfaceFilePath, atomically: true, encoding: String.Encoding.utf8)
|
|
// store snapshot
|
|
let snapshot = try self.documentManager.open(interfaceDocURI, language: .swift, version: 0, text: interfaceInfo.contents)
|
|
return await self.interfaceDetails(request: request, uri: interfaceDocURI, snapshot: snapshot, symbol: symbol)
|
|
} catch {
|
|
throw ResponseError.unknown(error.localizedDescription)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Open the Swift interface for a module.
|
|
///
|
|
/// - Parameters:
|
|
/// - request: The OpenInterfaceRequest.
|
|
/// - uri: The document whose compiler arguments should be used to generate the interface.
|
|
/// - name: The name of the module whose interface should be generated.
|
|
/// - interfaceURI: The file where the generated interface should be written.
|
|
private func openInterface(
|
|
request: OpenInterfaceRequest,
|
|
uri: DocumentURI,
|
|
name: String,
|
|
interfaceURI: DocumentURI
|
|
) async throws -> InterfaceInfo {
|
|
let keys = self.keys
|
|
let skreq = SKDRequestDictionary(sourcekitd: sourcekitd)
|
|
skreq[keys.request] = requests.editor_open_interface
|
|
skreq[keys.modulename] = name
|
|
if request.groupNames.count > 0 {
|
|
skreq[keys.groupname] = request.groupNames
|
|
}
|
|
skreq[keys.name] = interfaceURI.pseudoPath
|
|
skreq[keys.synthesizedextensions] = 1
|
|
if let compileCommand = await self.buildSettings(for: uri) {
|
|
skreq[keys.compilerargs] = compileCommand.compilerArgs
|
|
}
|
|
|
|
let dict = try await self.sourcekitd.send(skreq)
|
|
return InterfaceInfo(contents: dict[keys.sourcetext] ?? "")
|
|
}
|
|
|
|
private func interfaceDetails(
|
|
request: OpenInterfaceRequest,
|
|
uri: DocumentURI,
|
|
snapshot: DocumentSnapshot,
|
|
symbol: String?
|
|
) async -> InterfaceDetails {
|
|
do {
|
|
guard let symbol = symbol else {
|
|
return InterfaceDetails(uri: uri, position: nil)
|
|
}
|
|
let keys = self.keys
|
|
let skreq = SKDRequestDictionary(sourcekitd: sourcekitd)
|
|
|
|
skreq[keys.request] = requests.find_usr
|
|
skreq[keys.sourcefile] = uri.pseudoPath
|
|
skreq[keys.usr] = symbol
|
|
|
|
let dict = try await self.sourcekitd.send(skreq)
|
|
if let offset: Int = dict[keys.offset],
|
|
let position = snapshot.positionOf(utf8Offset: offset) {
|
|
return InterfaceDetails(uri: uri, position: position)
|
|
} else {
|
|
return InterfaceDetails(uri: uri, position: nil)
|
|
}
|
|
} catch {
|
|
return InterfaceDetails(uri: uri, position: nil)
|
|
}
|
|
}
|
|
}
|