@@ -20,6 +20,7 @@ import Markdown
20
20
import SKUtilities
21
21
import SourceKitLSP
22
22
import SemanticIndex
23
+ import SKLogging
23
24
24
25
extension DocumentationLanguageService {
25
26
package func doccDocumentation( _ req: DoccDocumentationRequest ) async throws -> DoccDocumentationResponse {
@@ -29,7 +30,6 @@ extension DocumentationLanguageService {
29
30
guard let workspace = await sourceKitLSPServer. workspaceForDocument ( uri: req. textDocument. uri) else {
30
31
throw ResponseError . workspaceNotOpen ( req. textDocument. uri)
31
32
}
32
- let documentationManager = workspace. doccDocumentationManager
33
33
let snapshot = try documentManager. latestSnapshot ( req. textDocument. uri)
34
34
var moduleName : String ? = nil
35
35
var catalogURL : URL ? = nil
@@ -40,81 +40,197 @@ extension DocumentationLanguageService {
40
40
41
41
switch snapshot. language {
42
42
case . tutorial:
43
- return try await documentationManager. renderDocCDocumentation (
44
- tutorialFile: snapshot. text,
43
+ return try await tutorialDocumentation (
44
+ for: snapshot,
45
+ in: workspace,
45
46
moduleName: moduleName,
46
47
catalogURL: catalogURL
47
48
)
48
49
case . markdown:
49
- guard case . symbol( let symbolName) = MarkdownTitleFinder . find ( parsing: snapshot. text) else {
50
- // This is an article that can be rendered on its own
51
- return try await documentationManager. renderDocCDocumentation (
52
- markupFile: snapshot. text,
53
- moduleName: moduleName,
54
- catalogURL: catalogURL
55
- )
50
+ return try await markdownDocumentation (
51
+ for: snapshot,
52
+ in: workspace,
53
+ moduleName: moduleName,
54
+ catalogURL: catalogURL
55
+ )
56
+ case . swift:
57
+ guard let position = req. position else {
58
+ throw ResponseError . invalidParams ( " A position must be provided for Swift files " )
56
59
}
57
- guard let moduleName, symbolName == moduleName else {
58
- // This is a symbol extension page. Find the symbol so that we can include it in the request.
59
- guard let index = workspace. index ( checkedFor: . deletedFiles) else {
60
- throw ResponseError . requestFailed ( doccDocumentationError: . indexNotAvailable)
61
- }
62
- guard let symbolLink = DocCSymbolLink ( linkString: symbolName) ,
63
- let symbolOccurrence = try await index. primaryDefinitionOrDeclarationOccurrence (
64
- ofDocCSymbolLink: symbolLink,
65
- fetchSymbolGraph: { location in
66
- guard let symbolWorkspace = try await workspaceForDocument ( uri: location. documentUri) else {
67
- throw ResponseError . internalError ( " Unable to find language service for \( location. documentUri) " )
68
- }
69
- let languageService = try await sourceKitLSPServer. primaryLanguageService (
70
- for: location. documentUri,
71
- . swift,
72
- in: symbolWorkspace
73
- )
74
- return try await languageService. symbolGraph ( forOnDiskContentsOf: location. documentUri, at: location)
60
+
61
+ return try await swiftDocumentation (
62
+ for: snapshot,
63
+ at: position,
64
+ in: workspace,
65
+ moduleName: moduleName,
66
+ catalogURL: catalogURL
67
+ )
68
+ default :
69
+ throw ResponseError . requestFailed ( doccDocumentationError: . unsupportedLanguage( snapshot. language) )
70
+ }
71
+ }
72
+
73
+ private func tutorialDocumentation(
74
+ for snapshot: DocumentSnapshot ,
75
+ in workspace: Workspace ,
76
+ moduleName: String ? ,
77
+ catalogURL: URL ?
78
+ ) async throws -> DoccDocumentationResponse {
79
+ return try await workspace. doccDocumentationManager. renderDocCDocumentation (
80
+ tutorialFile: snapshot. text,
81
+ moduleName: moduleName,
82
+ catalogURL: catalogURL
83
+ )
84
+ }
85
+
86
+ private func markdownDocumentation(
87
+ for snapshot: DocumentSnapshot ,
88
+ in workspace: Workspace ,
89
+ moduleName: String ? ,
90
+ catalogURL: URL ?
91
+ ) async throws -> DoccDocumentationResponse {
92
+ guard let sourceKitLSPServer else {
93
+ throw ResponseError . internalError ( " SourceKit-LSP is shutting down " )
94
+ }
95
+ let documentationManager = workspace. doccDocumentationManager
96
+ guard case . symbol( let symbolName) = MarkdownTitleFinder . find ( parsing: snapshot. text) else {
97
+ // This is an article that can be rendered on its own
98
+ return try await documentationManager. renderDocCDocumentation (
99
+ markupFile: snapshot. text,
100
+ moduleName: moduleName,
101
+ catalogURL: catalogURL
102
+ )
103
+ }
104
+ guard let moduleName, symbolName == moduleName else {
105
+ // This is a symbol extension page. Find the symbol so that we can include it in the request.
106
+ guard let index = workspace. index ( checkedFor: . deletedFiles) else {
107
+ throw ResponseError . requestFailed ( doccDocumentationError: . indexNotAvailable)
108
+ }
109
+ guard let symbolLink = DocCSymbolLink ( linkString: symbolName) ,
110
+ let symbolOccurrence = try await index. primaryDefinitionOrDeclarationOccurrence (
111
+ ofDocCSymbolLink: symbolLink,
112
+ fetchSymbolGraph: { location in
113
+ guard let symbolWorkspace = try await workspaceForDocument ( uri: location. documentUri) else {
114
+ throw ResponseError . internalError ( " Unable to find language service for \( location. documentUri) " )
75
115
}
76
- )
77
- else {
78
- throw ResponseError . requestFailed ( doccDocumentationError: . symbolNotFound( symbolName) )
79
- }
80
- let symbolDocumentUri = symbolOccurrence. location. documentUri
81
- guard let symbolWorkspace = try await workspaceForDocument ( uri: symbolDocumentUri) else {
82
- throw ResponseError . internalError ( " Unable to find language service for \( symbolDocumentUri) " )
83
- }
84
- let languageService = try await sourceKitLSPServer. primaryLanguageService (
85
- for: symbolDocumentUri,
86
- . swift,
87
- in: symbolWorkspace
88
- )
89
- let symbolGraph = try await languageService. symbolGraph (
90
- forOnDiskContentsOf: symbolDocumentUri,
91
- at: symbolOccurrence. location
92
- )
93
- guard let symbolGraph else {
94
- throw ResponseError . internalError ( " Unable to retrieve symbol graph for \( symbolOccurrence. symbol. name) " )
95
- }
96
- return try await documentationManager. renderDocCDocumentation (
97
- symbolUSR: symbolOccurrence. symbol. usr,
98
- symbolGraph: symbolGraph,
99
- markupFile: snapshot. text,
100
- moduleName: moduleName,
101
- catalogURL: catalogURL
116
+ let languageService = try await sourceKitLSPServer. primaryLanguageService (
117
+ for: location. documentUri,
118
+ . swift,
119
+ in: symbolWorkspace
120
+ )
121
+ return try await languageService. symbolGraph (
122
+ forOnDiskContentsOf: location. documentUri,
123
+ at: location
124
+ )
125
+ }
102
126
)
127
+ else {
128
+ throw ResponseError . requestFailed ( doccDocumentationError: . symbolNotFound( symbolName) )
103
129
}
104
- // This is a page representing the module itself.
105
- // Create a dummy symbol graph and tell SwiftDocC to convert the module name.
106
- // The version information isn't really all that important since we're creating
107
- // what is essentially an empty symbol graph.
130
+ let symbolDocumentUri = symbolOccurrence. location. documentUri
131
+ guard let symbolWorkspace = try await workspaceForDocument ( uri: symbolDocumentUri) else {
132
+ throw ResponseError . internalError ( " Unable to find language service for \( symbolDocumentUri) " )
133
+ }
134
+ let languageService = try await sourceKitLSPServer. primaryLanguageService (
135
+ for: symbolDocumentUri,
136
+ . swift,
137
+ in: symbolWorkspace
138
+ )
139
+ let symbolGraph = try await languageService. symbolGraph (
140
+ forOnDiskContentsOf: symbolDocumentUri,
141
+ at: symbolOccurrence. location
142
+ )
108
143
return try await documentationManager. renderDocCDocumentation (
109
- symbolUSR: moduleName ,
110
- symbolGraph: emptySymbolGraph ( forModule : moduleName ) ,
144
+ symbolUSR: symbolOccurrence . symbol . usr ,
145
+ symbolGraph: symbolGraph ,
111
146
markupFile: snapshot. text,
112
147
moduleName: moduleName,
113
148
catalogURL: catalogURL
114
149
)
115
- default :
116
- throw ResponseError . requestFailed ( doccDocumentationError: . unsupportedLanguage( snapshot. language) )
117
150
}
151
+ // This is a page representing the module itself.
152
+ // Create a dummy symbol graph and tell SwiftDocC to convert the module name.
153
+ // The version information isn't really all that important since we're creating
154
+ // what is essentially an empty symbol graph.
155
+ return try await documentationManager. renderDocCDocumentation (
156
+ symbolUSR: moduleName,
157
+ symbolGraph: emptySymbolGraph ( forModule: moduleName) ,
158
+ markupFile: snapshot. text,
159
+ moduleName: moduleName,
160
+ catalogURL: catalogURL
161
+ )
162
+ }
163
+
164
+ private func swiftDocumentation(
165
+ for snapshot: DocumentSnapshot ,
166
+ at position: Position ,
167
+ in workspace: Workspace ,
168
+ moduleName: String ? ,
169
+ catalogURL: URL ?
170
+ ) async throws -> DoccDocumentationResponse {
171
+ guard let sourceKitLSPServer else {
172
+ throw ResponseError . internalError ( " SourceKit-LSP is shutting down " )
173
+ }
174
+ let documentationManager = workspace. doccDocumentationManager
175
+ let ( symbolGraph, symbolUSR, overrideDocComments) = try await sourceKitLSPServer. primaryLanguageService (
176
+ for: snapshot. uri,
177
+ snapshot. language,
178
+ in: workspace
179
+ ) . symbolGraph ( for: snapshot, at: position)
180
+ // Locate the documentation extension and include it in the request if one exists
181
+ let markupExtensionFile = await orLog ( " Finding markup extension file for symbol \( symbolUSR) " ) {
182
+ try await findMarkupExtensionFile (
183
+ workspace: workspace,
184
+ documentationManager: documentationManager,
185
+ catalogURL: catalogURL,
186
+ for: symbolUSR,
187
+ fetchSymbolGraph: { location in
188
+ guard let symbolWorkspace = try await workspaceForDocument ( uri: location. documentUri) else {
189
+ throw ResponseError . internalError ( " Unable to find language service for \( location. documentUri) " )
190
+ }
191
+ let languageService = try await sourceKitLSPServer. primaryLanguageService (
192
+ for: location. documentUri,
193
+ . swift,
194
+ in: symbolWorkspace
195
+ )
196
+ return try await languageService. symbolGraph ( forOnDiskContentsOf: location. documentUri, at: location)
197
+ }
198
+ )
199
+ }
200
+ return try await documentationManager. renderDocCDocumentation (
201
+ symbolUSR: symbolUSR,
202
+ symbolGraph: symbolGraph,
203
+ overrideDocComments: overrideDocComments,
204
+ markupFile: markupExtensionFile,
205
+ moduleName: moduleName,
206
+ catalogURL: catalogURL
207
+ )
208
+ }
209
+
210
+ private func findMarkupExtensionFile(
211
+ workspace: Workspace ,
212
+ documentationManager: DocCDocumentationManager ,
213
+ catalogURL: URL ? ,
214
+ for symbolUSR: String ,
215
+ fetchSymbolGraph: @Sendable ( SymbolLocation) async throws -> String ?
216
+ ) async throws -> String ? {
217
+ guard let catalogURL else {
218
+ return nil
219
+ }
220
+ let catalogIndex = try await documentationManager. catalogIndex ( for: catalogURL)
221
+ guard let index = workspace. index ( checkedFor: . deletedFiles) ,
222
+ let symbolInformation = try await index. doccSymbolInformation (
223
+ ofUSR: symbolUSR,
224
+ fetchSymbolGraph: fetchSymbolGraph
225
+ ) ,
226
+ let markupExtensionFileURL = catalogIndex. documentationExtension ( for: symbolInformation)
227
+ else {
228
+ return nil
229
+ }
230
+ return try ? documentManager. latestSnapshotOrDisk (
231
+ DocumentURI ( markupExtensionFileURL) ,
232
+ language: . markdown
233
+ ) ? . text
118
234
}
119
235
}
120
236
0 commit comments