File: OpenInterface.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (114 lines) | stat: -rw-r--r-- 4,214 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//===----------------------------------------------------------------------===//
//
// 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 LSPLogging
import LanguageServerProtocol
import SKSupport
import SourceKitD

struct GeneratedInterfaceInfo {
  var contents: String
}

extension SwiftLanguageService {
  public func openGeneratedInterface(
    _ request: OpenGeneratedInterfaceRequest
  ) async throws -> GeneratedInterfaceDetails? {
    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 = try? self.documentManager.latestSnapshot(interfaceDocURI) {
      return await self.generatedInterfaceDetails(
        request: request,
        uri: interfaceDocURI,
        snapshot: snapshot,
        symbol: symbol
      )
    } else {
      let interfaceInfo = try await self.generatedInterfaceInfo(request: request, interfaceURI: interfaceDocURI)
      try interfaceInfo.contents.write(to: interfaceFilePath, atomically: true, encoding: String.Encoding.utf8)
      let snapshot = DocumentSnapshot(
        uri: interfaceDocURI,
        language: .swift,
        version: 0,
        lineTable: LineTable(interfaceInfo.contents)
      )
      let result = await self.generatedInterfaceDetails(
        request: request,
        uri: interfaceDocURI,
        snapshot: snapshot,
        symbol: symbol
      )
      _ = await orLog("Closing generated interface") {
        try await sendSourcekitdRequest(closeDocumentSourcekitdRequest(uri: interfaceDocURI), fileContents: nil)
      }
      return result
    }
  }

  /// Open the Swift interface for a module.
  ///
  /// - Parameters:
  ///   - request: The OpenGeneratedInterfaceRequest.
  ///   - interfaceURI: The file where the generated interface should be written.
  ///
  /// - Important: This opens a document with name `interfaceURI.pseudoPath` in sourcekitd. The caller is responsible
  ///   for ensuring that the document will eventually get closed in sourcekitd again.
  private func generatedInterfaceInfo(
    request: OpenGeneratedInterfaceRequest,
    interfaceURI: DocumentURI
  ) async throws -> GeneratedInterfaceInfo {
    let keys = self.keys
    let skreq = sourcekitd.dictionary([
      keys.request: requests.editorOpenInterface,
      keys.moduleName: request.moduleName,
      keys.groupName: request.groupName,
      keys.name: interfaceURI.pseudoPath,
      keys.synthesizedExtension: 1,
      keys.compilerArgs: await self.buildSettings(for: request.textDocument.uri)?.compilerArgs as [SKDRequestValue]?,
    ])

    let dict = try await sendSourcekitdRequest(skreq, fileContents: nil)
    return GeneratedInterfaceInfo(contents: dict[keys.sourceText] ?? "")
  }

  private func generatedInterfaceDetails(
    request: OpenGeneratedInterfaceRequest,
    uri: DocumentURI,
    snapshot: DocumentSnapshot,
    symbol: String?
  ) async -> GeneratedInterfaceDetails {
    do {
      guard let symbol = symbol else {
        return GeneratedInterfaceDetails(uri: uri, position: nil)
      }
      let keys = self.keys
      let skreq = sourcekitd.dictionary([
        keys.request: requests.editorFindUSR,
        keys.sourceFile: uri.pseudoPath,
        keys.usr: symbol,
      ])

      let dict = try await sendSourcekitdRequest(skreq, fileContents: snapshot.text)
      if let offset: Int = dict[keys.offset] {
        return GeneratedInterfaceDetails(uri: uri, position: snapshot.positionOf(utf8Offset: offset))
      } else {
        return GeneratedInterfaceDetails(uri: uri, position: nil)
      }
    } catch {
      return GeneratedInterfaceDetails(uri: uri, position: nil)
    }
  }
}