Skip to content

Commit aeb6c14

Browse files
authored
Merge pull request #1851 from matthewbastien/convert-documentation
Add `textDocument/doccDocumentation` request
2 parents bb699c9 + 561aad2 commit aeb6c14

File tree

14 files changed

+1208
-13
lines changed

14 files changed

+1208
-13
lines changed

Contributor Documentation/LSP Extensions.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,56 @@ interface SKCompletionOptions {
169169
}
170170
```
171171
172+
## `textDocument/doccDocumentation`
173+
174+
New request that generates documentation for a symbol at a given cursor location.
175+
176+
Primarily designed to support live preview of Swift documentation in editors.
177+
178+
This request looks up the nearest documentable symbol (if any) at a given cursor location within
179+
a text document and returns a `DoccDocumentationResponse`. The response contains a string
180+
representing single JSON encoded DocC RenderNode. This RenderNode can then be rendered in an
181+
editor via https://github.com/swiftlang/swift-docc-render.
182+
183+
The position may be ommitted for documentation within DocC markdown and tutorial files as they
184+
represent a single documentation page. It is only required for generating documentation within
185+
Swift files as they usually contain multiple documentable symbols.
186+
187+
Documentation can fail to be generated for a number of reasons. The most common of which being
188+
that no documentable symbol could be found. In such cases the request will fail with a request
189+
failed LSP error code (-32803) that contains a human-readable error message. This error message can
190+
be displayed within the live preview editor to indicate that something has gone wrong.
191+
192+
At the moment this request is only available on macOS and Linux. SourceKit-LSP will advertise
193+
`textDocument/doccDocumentation` in its experimental server capabilities if it supports it.
194+
195+
- params: `DoccDocumentationParams`
196+
- result: `DoccDocumentationResponse`
197+
198+
```ts
199+
export interface DoccDocumentationParams {
200+
/**
201+
* The document to generate documentation for.
202+
*/
203+
textDocument: TextDocumentIdentifier;
204+
205+
/**
206+
* The cursor position within the document. (optional)
207+
*
208+
* This parameter is only used in Swift files to determine which symbol to render.
209+
* The position is ignored for markdown and tutorial documents.
210+
*/
211+
position?: Position;
212+
}
213+
214+
export interface DoccDocumentationResponse {
215+
/**
216+
* The JSON encoded RenderNode that can be rendered by swift-docc-render.
217+
*/
218+
renderNode: string;
219+
}
220+
```
221+
172222
## `textDocument/symbolInfo`
173223
174224
New request for semantic information about the symbol at a given location.

Package.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ var targets: [Target] = [
474474
"SwiftExtensions",
475475
"ToolchainRegistry",
476476
"TSCExtensions",
477+
.product(name: "SwiftDocC", package: "swift-docc"),
477478
.product(name: "IndexStoreDB", package: "indexstore-db"),
478479
.product(name: "Crypto", package: "swift-crypto"),
479480
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
@@ -752,6 +753,7 @@ var dependencies: [Package.Dependency] {
752753
} else if useLocalDependencies {
753754
return [
754755
.package(path: "../indexstore-db"),
756+
.package(path: "../swift-docc"),
755757
.package(path: "../swift-tools-support-core"),
756758
.package(path: "../swift-argument-parser"),
757759
.package(path: "../swift-syntax"),
@@ -762,6 +764,7 @@ var dependencies: [Package.Dependency] {
762764

763765
return [
764766
.package(url: "https://github.com/swiftlang/indexstore-db.git", branch: relatedDependenciesBranch),
767+
.package(url: "https://github.com/swiftlang/swift-docc.git", branch: relatedDependenciesBranch),
765768
.package(url: "https://github.com/apple/swift-tools-support-core.git", branch: relatedDependenciesBranch),
766769
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.4.0"),
767770
.package(url: "https://github.com/swiftlang/swift-syntax.git", branch: relatedDependenciesBranch),

Sources/LanguageServerProtocol/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ add_library(LanguageServerProtocol STATIC
4242
Requests/DeclarationRequest.swift
4343
Requests/DefinitionRequest.swift
4444
Requests/DiagnosticsRefreshRequest.swift
45+
Requests/DoccDocumentationRequest.swift
4546
Requests/DocumentColorRequest.swift
4647
Requests/DocumentDiagnosticsRequest.swift
4748
Requests/DocumentHighlightRequest.swift

Sources/LanguageServerProtocol/Error.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ extension ResponseError {
112112
return ResponseError(code: .workspaceNotOpen, message: "No workspace containing '\(uri)' found")
113113
}
114114

115+
public static func invalidParams(_ message: String) -> ResponseError {
116+
return ResponseError(code: .invalidParams, message: message)
117+
}
118+
115119
public static func methodNotFound(_ method: String) -> ResponseError {
116120
return ResponseError(code: .methodNotFound, message: "method not found: \(method)")
117121
}
@@ -120,6 +124,10 @@ extension ResponseError {
120124
return ResponseError(code: .unknownErrorCode, message: message)
121125
}
122126

127+
public static func requestFailed(_ message: String) -> ResponseError {
128+
return ResponseError(code: .requestFailed, message: message)
129+
}
130+
123131
public static func internalError(_ message: String) -> ResponseError {
124132
return ResponseError(code: .internalError, message: message)
125133
}

Sources/LanguageServerProtocol/Messages.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public let builtinRequests: [_RequestType.Type] = [
3333
DeclarationRequest.self,
3434
DefinitionRequest.self,
3535
DiagnosticsRefreshRequest.self,
36+
DoccDocumentationRequest.self,
3637
DocumentColorRequest.self,
3738
DocumentDiagnosticsRequest.self,
3839
DocumentFormattingRequest.self,
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// Request that generates documentation for a symbol at a given cursor location **(LSP Extension)**.
14+
///
15+
/// Primarily designed to support live preview of Swift documentation in editors.
16+
///
17+
/// This request looks up the nearest documentable symbol (if any) at a given cursor location within
18+
/// a text document and returns a `DoccDocumentationResponse`. The response contains a string
19+
/// representing single JSON encoded DocC RenderNode. This RenderNode can then be rendered in an
20+
/// editor via https://github.com/swiftlang/swift-docc-render.
21+
///
22+
/// The position may be ommitted for documentation within DocC markdown and tutorial files as they
23+
/// represent a single documentation page. It is only required for generating documentation within
24+
/// Swift files as they usually contain multiple documentable symbols.
25+
///
26+
/// Documentation can fail to be generated for a number of reasons. The most common of which being
27+
/// that no documentable symbol could be found. In such cases the request will fail with a request
28+
/// failed LSP error code (-32803) that contains a human-readable error message. This error message can
29+
/// be displayed within the live preview editor to indicate that something has gone wrong.
30+
///
31+
/// At the moment this request is only available on macOS and Linux. SourceKit-LSP will advertise
32+
/// `textDocument/doccDocumentation` in its experimental server capabilities if it supports it.
33+
///
34+
/// - Parameters:
35+
/// - textDocument: The document to generate documentation for.
36+
/// - position: The cursor position within the document. (optional)
37+
///
38+
/// - Returns: A `DoccDocumentationResponse` for the given location, which may contain an error
39+
/// message if documentation could not be converted. This error message can be displayed to the user
40+
/// in the live preview editor.
41+
///
42+
/// ### LSP Extension
43+
///
44+
/// This request is an extension to LSP supported by SourceKit-LSP.
45+
/// The client is expected to display the documentation in an editor using swift-docc-render.
46+
public struct DoccDocumentationRequest: TextDocumentRequest, Hashable {
47+
public static let method: String = "textDocument/doccDocumentation"
48+
public typealias Response = DoccDocumentationResponse
49+
50+
/// The document in which to lookup the symbol location.
51+
public var textDocument: TextDocumentIdentifier
52+
53+
/// The document location at which to lookup symbol information.
54+
public var position: Position?
55+
56+
public init(textDocument: TextDocumentIdentifier, position: Position? = nil) {
57+
self.textDocument = textDocument
58+
self.position = position
59+
}
60+
}
61+
62+
public struct DoccDocumentationResponse: ResponseType, Equatable {
63+
public var renderNode: String
64+
65+
public init(renderNode: String) {
66+
self.renderNode = renderNode
67+
}
68+
}

Sources/SKTestSupport/TestSourceKitLSPClient.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,16 +238,17 @@ package final class TestSourceKitLSPClient: MessageHandler, Sendable {
238238
// MARK: - Sending messages
239239

240240
/// Send the request to `server` and return the request result.
241-
package func send<R: RequestType>(_ request: R) async throws -> R.Response {
242-
return try await withCheckedThrowingContinuation { continuation in
241+
package func send<R: RequestType>(_ request: R) async throws(ResponseError) -> R.Response {
242+
let response = await withCheckedContinuation { continuation in
243243
self.send(request) { result in
244-
continuation.resume(with: result)
244+
continuation.resume(returning: result)
245245
}
246246
}
247+
return try response.get()
247248
}
248249

249250
/// Variant of `send` above that allows the response to be discarded if it is a `VoidResponse`.
250-
package func send<R: RequestType>(_ request: R) async throws where R.Response == VoidResponse {
251+
package func send<R: RequestType>(_ request: R) async throws(ResponseError) where R.Response == VoidResponse {
251252
let _: VoidResponse = try await self.send(request)
252253
}
253254

0 commit comments

Comments
 (0)