Skip to content

Commit

Permalink
Merge pull request #1851 from matthewbastien/convert-documentation
Browse files Browse the repository at this point in the history
Add `textDocument/doccDocumentation` request
  • Loading branch information
ahoppen authored Jan 20, 2025
2 parents bb699c9 + 561aad2 commit aeb6c14
Show file tree
Hide file tree
Showing 14 changed files with 1,208 additions and 13 deletions.
50 changes: 50 additions & 0 deletions Contributor Documentation/LSP Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,56 @@ interface SKCompletionOptions {
}
```
## `textDocument/doccDocumentation`
New request that generates documentation for a symbol at a given cursor location.
Primarily designed to support live preview of Swift documentation in editors.
This request looks up the nearest documentable symbol (if any) at a given cursor location within
a text document and returns a `DoccDocumentationResponse`. The response contains a string
representing single JSON encoded DocC RenderNode. This RenderNode can then be rendered in an
editor via https://github.com/swiftlang/swift-docc-render.
The position may be ommitted for documentation within DocC markdown and tutorial files as they
represent a single documentation page. It is only required for generating documentation within
Swift files as they usually contain multiple documentable symbols.
Documentation can fail to be generated for a number of reasons. The most common of which being
that no documentable symbol could be found. In such cases the request will fail with a request
failed LSP error code (-32803) that contains a human-readable error message. This error message can
be displayed within the live preview editor to indicate that something has gone wrong.
At the moment this request is only available on macOS and Linux. SourceKit-LSP will advertise
`textDocument/doccDocumentation` in its experimental server capabilities if it supports it.
- params: `DoccDocumentationParams`
- result: `DoccDocumentationResponse`
```ts
export interface DoccDocumentationParams {
/**
* The document to generate documentation for.
*/
textDocument: TextDocumentIdentifier;

/**
* The cursor position within the document. (optional)
*
* This parameter is only used in Swift files to determine which symbol to render.
* The position is ignored for markdown and tutorial documents.
*/
position?: Position;
}

export interface DoccDocumentationResponse {
/**
* The JSON encoded RenderNode that can be rendered by swift-docc-render.
*/
renderNode: string;
}
```
## `textDocument/symbolInfo`
New request for semantic information about the symbol at a given location.
Expand Down
3 changes: 3 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ var targets: [Target] = [
"SwiftExtensions",
"ToolchainRegistry",
"TSCExtensions",
.product(name: "SwiftDocC", package: "swift-docc"),
.product(name: "IndexStoreDB", package: "indexstore-db"),
.product(name: "Crypto", package: "swift-crypto"),
.product(name: "SwiftToolsSupport-auto", package: "swift-tools-support-core"),
Expand Down Expand Up @@ -752,6 +753,7 @@ var dependencies: [Package.Dependency] {
} else if useLocalDependencies {
return [
.package(path: "../indexstore-db"),
.package(path: "../swift-docc"),
.package(path: "../swift-tools-support-core"),
.package(path: "../swift-argument-parser"),
.package(path: "../swift-syntax"),
Expand All @@ -762,6 +764,7 @@ var dependencies: [Package.Dependency] {

return [
.package(url: "https://github.com/swiftlang/indexstore-db.git", branch: relatedDependenciesBranch),
.package(url: "https://github.com/swiftlang/swift-docc.git", branch: relatedDependenciesBranch),
.package(url: "https://github.com/apple/swift-tools-support-core.git", branch: relatedDependenciesBranch),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.4.0"),
.package(url: "https://github.com/swiftlang/swift-syntax.git", branch: relatedDependenciesBranch),
Expand Down
1 change: 1 addition & 0 deletions Sources/LanguageServerProtocol/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ add_library(LanguageServerProtocol STATIC
Requests/DeclarationRequest.swift
Requests/DefinitionRequest.swift
Requests/DiagnosticsRefreshRequest.swift
Requests/DoccDocumentationRequest.swift
Requests/DocumentColorRequest.swift
Requests/DocumentDiagnosticsRequest.swift
Requests/DocumentHighlightRequest.swift
Expand Down
8 changes: 8 additions & 0 deletions Sources/LanguageServerProtocol/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ extension ResponseError {
return ResponseError(code: .workspaceNotOpen, message: "No workspace containing '\(uri)' found")
}

public static func invalidParams(_ message: String) -> ResponseError {
return ResponseError(code: .invalidParams, message: message)
}

public static func methodNotFound(_ method: String) -> ResponseError {
return ResponseError(code: .methodNotFound, message: "method not found: \(method)")
}
Expand All @@ -120,6 +124,10 @@ extension ResponseError {
return ResponseError(code: .unknownErrorCode, message: message)
}

public static func requestFailed(_ message: String) -> ResponseError {
return ResponseError(code: .requestFailed, message: message)
}

public static func internalError(_ message: String) -> ResponseError {
return ResponseError(code: .internalError, message: message)
}
Expand Down
1 change: 1 addition & 0 deletions Sources/LanguageServerProtocol/Messages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public let builtinRequests: [_RequestType.Type] = [
DeclarationRequest.self,
DefinitionRequest.self,
DiagnosticsRefreshRequest.self,
DoccDocumentationRequest.self,
DocumentColorRequest.self,
DocumentDiagnosticsRequest.self,
DocumentFormattingRequest.self,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 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
//
//===----------------------------------------------------------------------===//

/// Request that generates documentation for a symbol at a given cursor location **(LSP Extension)**.
///
/// Primarily designed to support live preview of Swift documentation in editors.
///
/// This request looks up the nearest documentable symbol (if any) at a given cursor location within
/// a text document and returns a `DoccDocumentationResponse`. The response contains a string
/// representing single JSON encoded DocC RenderNode. This RenderNode can then be rendered in an
/// editor via https://github.com/swiftlang/swift-docc-render.
///
/// The position may be ommitted for documentation within DocC markdown and tutorial files as they
/// represent a single documentation page. It is only required for generating documentation within
/// Swift files as they usually contain multiple documentable symbols.
///
/// Documentation can fail to be generated for a number of reasons. The most common of which being
/// that no documentable symbol could be found. In such cases the request will fail with a request
/// failed LSP error code (-32803) that contains a human-readable error message. This error message can
/// be displayed within the live preview editor to indicate that something has gone wrong.
///
/// At the moment this request is only available on macOS and Linux. SourceKit-LSP will advertise
/// `textDocument/doccDocumentation` in its experimental server capabilities if it supports it.
///
/// - Parameters:
/// - textDocument: The document to generate documentation for.
/// - position: The cursor position within the document. (optional)
///
/// - Returns: A `DoccDocumentationResponse` for the given location, which may contain an error
/// message if documentation could not be converted. This error message can be displayed to the user
/// in the live preview editor.
///
/// ### LSP Extension
///
/// This request is an extension to LSP supported by SourceKit-LSP.
/// The client is expected to display the documentation in an editor using swift-docc-render.
public struct DoccDocumentationRequest: TextDocumentRequest, Hashable {
public static let method: String = "textDocument/doccDocumentation"
public typealias Response = DoccDocumentationResponse

/// The document in which to lookup the symbol location.
public var textDocument: TextDocumentIdentifier

/// The document location at which to lookup symbol information.
public var position: Position?

public init(textDocument: TextDocumentIdentifier, position: Position? = nil) {
self.textDocument = textDocument
self.position = position
}
}

public struct DoccDocumentationResponse: ResponseType, Equatable {
public var renderNode: String

public init(renderNode: String) {
self.renderNode = renderNode
}
}
9 changes: 5 additions & 4 deletions Sources/SKTestSupport/TestSourceKitLSPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -238,16 +238,17 @@ package final class TestSourceKitLSPClient: MessageHandler, Sendable {
// MARK: - Sending messages

/// Send the request to `server` and return the request result.
package func send<R: RequestType>(_ request: R) async throws -> R.Response {
return try await withCheckedThrowingContinuation { continuation in
package func send<R: RequestType>(_ request: R) async throws(ResponseError) -> R.Response {
let response = await withCheckedContinuation { continuation in
self.send(request) { result in
continuation.resume(with: result)
continuation.resume(returning: result)
}
}
return try response.get()
}

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

Expand Down
Loading

0 comments on commit aeb6c14

Please sign in to comment.