Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename getReferenceDocument request to textDocumentContent #1639

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
27 changes: 0 additions & 27 deletions Contributor Documentation/LSP Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -595,30 +595,3 @@ export interface PeekDocumentsResult {
success: boolean;
}
```

## `workspace/getReferenceDocument`
fwcd marked this conversation as resolved.
Show resolved Hide resolved

Request from the client to the server asking for contents of a URI having a custom scheme.
For example: "sourcekit-lsp:"

Enable the experimental client capability `"workspace/getReferenceDocument"` so that the server responds with reference document URLs for certain requests or commands whenever possible.

- params: `GetReferenceDocumentParams`

- result: `GetReferenceDocumentResponse`

```ts
export interface GetReferenceDocumentParams {
/**
* The `DocumentUri` of the custom scheme url for which content is required
*/
uri: DocumentUri;
}

/**
* Response containing `content` of `GetReferenceDocumentRequest`
*/
export interface GetReferenceDocumentResult {
content: string;
}
```
2 changes: 1 addition & 1 deletion Sources/LanguageServerProtocol/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ add_library(LanguageServerProtocol STATIC
Requests/ExecuteCommandRequest.swift
Requests/FoldingRangeRequest.swift
Requests/FormattingRequests.swift
Requests/GetReferenceDocumentRequest.swift
Requests/HoverRequest.swift
Requests/ImplementationRequest.swift
Requests/IndexedRenameRequest.swift
Expand All @@ -79,6 +78,7 @@ add_library(LanguageServerProtocol STATIC
Requests/ShutdownRequest.swift
Requests/SignatureHelpRequest.swift
Requests/SymbolInfoRequest.swift
Requests/TextDocumentContentRequest.swift
Requests/TriggerReindexRequest.swift
Requests/TypeDefinitionRequest.swift
Requests/TypeHierarchyPrepareRequest.swift
Expand Down
2 changes: 1 addition & 1 deletion Sources/LanguageServerProtocol/Messages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ public let builtinRequests: [_RequestType.Type] = [
DocumentTestsRequest.self,
ExecuteCommandRequest.self,
FoldingRangeRequest.self,
GetReferenceDocumentRequest.self,
HoverRequest.self,
ImplementationRequest.self,
InitializeRequest.self,
Expand All @@ -71,6 +70,7 @@ public let builtinRequests: [_RequestType.Type] = [
ShutdownRequest.self,
SignatureHelpRequest.self,
SymbolInfoRequest.self,
TextDocumentContentRequest.self,
TriggerReindexRequest.self,
TypeDefinitionRequest.self,
TypeHierarchyPrepareRequest.self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@
//
//===----------------------------------------------------------------------===//

/// Request from the client to the server asking for contents of a URI having a custom scheme **(LSP Extension)**
/// Request from the client to the server asking for contents of a URI having a custom scheme
/// For example: "sourcekit-lsp:"
///
/// - Parameters:
/// - uri: The `DocumentUri` of the custom scheme url for which content is required
///
/// - Returns: `GetReferenceDocumentResponse` which contains the `content` to be displayed.
/// - Returns: `TextDocumentContentResponse` which contains the `content` to be displayed.
///
/// ### LSP Extension
///
/// This request is an extension to LSP supported by SourceKit-LSP.
/// Enable the experimental client capability `"workspace/getReferenceDocument"` so that the server responds with
/// Enable the experimental client capability `"workspace/textDocumentContent"` so that the server responds with
/// reference document URLs for certain requests or commands whenever possible.
fwcd marked this conversation as resolved.
Show resolved Hide resolved
public struct GetReferenceDocumentRequest: RequestType {
public static let method: String = "workspace/getReferenceDocument"
public typealias Response = GetReferenceDocumentResponse
public struct TextDocumentContentRequest: RequestType {
public static let method: String = "workspace/textDocumentContent"
public typealias Response = TextDocumentContentResponse

public var uri: DocumentURI

Expand All @@ -34,11 +34,11 @@ public struct GetReferenceDocumentRequest: RequestType {
}
}

/// Response containing `content` of `GetReferenceDocumentRequest`
public struct GetReferenceDocumentResponse: ResponseType {
public var content: String
/// Response containing `text` of `TextDocumentContentRequest`
public struct TextDocumentContentResponse: ResponseType {
public var text: String
fwcd marked this conversation as resolved.
Show resolved Hide resolved

public init(content: String) {
self.content = content
public init(text: String) {
self.text = text
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ public struct WorkspaceClientCapabilities: Hashable, Codable, Sendable {

public var diagnostics: RefreshRegistrationCapability? = nil

public var textDocumentContent: DynamicRegistrationCapability? = nil

public init(
applyEdit: Bool? = nil,
workspaceEdit: WorkspaceEdit? = nil,
Expand All @@ -202,7 +204,8 @@ public struct WorkspaceClientCapabilities: Hashable, Codable, Sendable {
fileOperations: FileOperations? = nil,
inlineValue: RefreshRegistrationCapability? = nil,
inlayHint: RefreshRegistrationCapability? = nil,
diagnostics: RefreshRegistrationCapability? = nil
diagnostics: RefreshRegistrationCapability? = nil,
textDocumentContent: DynamicRegistrationCapability? = nil
) {
self.applyEdit = applyEdit
self.workspaceEdit = workspaceEdit
Expand All @@ -218,6 +221,7 @@ public struct WorkspaceClientCapabilities: Hashable, Codable, Sendable {
self.inlineValue = inlineValue
self.inlayHint = inlayHint
self.diagnostics = diagnostics
self.textDocumentContent = textDocumentContent
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1219,10 +1219,27 @@ public struct WorkspaceServerCapabilities: Codable, Hashable, Sendable {
public var willDelete: FileOperationRegistrationOptions?
}

/// Text document content provider options.
public struct TextDocumentContentOptions: Codable, Hashable, Sendable {
/// The schemes for which the server provides content.
public var schemes: [String]

public init(schemes: [String] = []) {
self.schemes = schemes
}
}

/// The server supports workspace folder.
public var workspaceFolders: WorkspaceFolders?

public init(workspaceFolders: WorkspaceFolders? = nil) {
/// The server supports the `workspace/textDocumentContent` request.
public var textDocumentContent: TextDocumentContentOptions?

public init(
workspaceFolders: WorkspaceFolders? = nil,
textDocumentContent: TextDocumentContentOptions? = nil
) {
self.workspaceFolders = workspaceFolders
self.textDocumentContent = textDocumentContent
}
}
2 changes: 1 addition & 1 deletion Sources/SourceKitLSP/Clang/ClangLanguageService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ extension ClangLanguageService {
return try await forwardRequestToClangd(req)
}

func getReferenceDocument(_ req: GetReferenceDocumentRequest) async throws -> GetReferenceDocumentResponse {
func textDocumentContent(_ req: TextDocumentContentRequest) async throws -> TextDocumentContentResponse {
throw ResponseError.unknown("unsupported method")
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/SourceKitLSP/LanguageService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ package protocol LanguageService: AnyObject, Sendable {

func executeCommand(_ req: ExecuteCommandRequest) async throws -> LSPAny?

func getReferenceDocument(_ req: GetReferenceDocumentRequest) async throws -> GetReferenceDocumentResponse
func textDocumentContent(_ req: TextDocumentContentRequest) async throws -> TextDocumentContentResponse

/// Perform a syntactic scan of the file at the given URI for test cases and test classes.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ enum MessageHandlingDependencyTracker: DependencyTracker {
} else {
self = .freestanding
}
case let request as GetReferenceDocumentRequest:
case let request as TextDocumentContentRequest:
self = .documentRequest(request.uri)
case is InitializeRequest:
self = .globalConfigurationChange
Expand Down
23 changes: 7 additions & 16 deletions Sources/SourceKitLSP/SourceKitLSPServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -746,8 +746,8 @@ extension SourceKitLSPServer: MessageHandler {
await request.reply { try await executeCommand(request.params) }
case let request as RequestAndReply<FoldingRangeRequest>:
await self.handleRequest(for: request, requestHandler: self.foldingRange)
case let request as RequestAndReply<GetReferenceDocumentRequest>:
await request.reply { try await getReferenceDocument(request.params) }
case let request as RequestAndReply<TextDocumentContentRequest>:
await request.reply { try await textDocumentContent(request.params) }
case let request as RequestAndReply<HoverRequest>:
await self.handleRequest(for: request, requestHandler: self.hover)
case let request as RequestAndReply<ImplementationRequest>:
Expand Down Expand Up @@ -986,8 +986,6 @@ extension SourceKitLSPServer {
//
// The below is a workaround for the vscode-swift extension since it cannot set client capabilities.
// It passes "workspace/peekDocuments" through the `initializationOptions`.
//
// Similarly, for "workspace/getReferenceDocument".
var clientCapabilities = req.capabilities
if case .dictionary(let initializationOptions) = req.initializationOptions {
if let peekDocuments = initializationOptions["workspace/peekDocuments"] {
Expand All @@ -999,15 +997,6 @@ extension SourceKitLSPServer {
}
}

if let getReferenceDocument = initializationOptions["workspace/getReferenceDocument"] {
if case .dictionary(var experimentalCapabilities) = clientCapabilities.experimental {
experimentalCapabilities["workspace/getReferenceDocument"] = getReferenceDocument
clientCapabilities.experimental = .dictionary(experimentalCapabilities)
} else {
clientCapabilities.experimental = .dictionary(["workspace/getReferenceDocument": getReferenceDocument])
}
}

// The client announces what CodeLenses it supports, and the LSP will only return
// ones found in the supportedCommands dictionary.
if let codeLens = initializationOptions["textDocument/codeLens"],
Expand Down Expand Up @@ -1166,6 +1155,9 @@ extension SourceKitLSPServer {
workspaceFolders: .init(
supported: true,
changeNotifications: .bool(true)
),
textDocumentContent: .init(
schemes: [ReferenceDocumentURL.scheme]
)
),
callHierarchyProvider: .bool(true),
Expand All @@ -1176,7 +1168,6 @@ extension SourceKitLSPServer {
"workspace/tests": .dictionary(["version": .int(2)]),
"textDocument/tests": .dictionary(["version": .int(2)]),
"workspace/triggerReindex": .dictionary(["version": .int(1)]),
"workspace/getReferenceDocument": .dictionary(["version": .int(1)]),
])
)
}
Expand Down Expand Up @@ -1744,7 +1735,7 @@ extension SourceKitLSPServer {
return try await languageService.executeCommand(executeCommand)
}

func getReferenceDocument(_ req: GetReferenceDocumentRequest) async throws -> GetReferenceDocumentResponse {
func textDocumentContent(_ req: TextDocumentContentRequest) async throws -> TextDocumentContentResponse {
let primaryFileURI = try ReferenceDocumentURL(from: req.uri).primaryFile

guard let workspace = await workspaceForDocument(uri: primaryFileURI) else {
Expand All @@ -1755,7 +1746,7 @@ extension SourceKitLSPServer {
throw ResponseError.unknown("No Language Service for URI: \(primaryFileURI)")
}

return try await languageService.getReferenceDocument(req)
return try await languageService.textDocumentContent(req)
}

func codeAction(
Expand Down
4 changes: 2 additions & 2 deletions Sources/SourceKitLSP/Swift/MacroExpansion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ extension SwiftLanguageService {
}

if case .dictionary(let experimentalCapabilities) = self.capabilityRegistry.clientCapabilities.experimental,
case .bool(true) = experimentalCapabilities["workspace/peekDocuments"],
case .bool(true) = experimentalCapabilities["workspace/getReferenceDocument"]
case .bool(true) = experimentalCapabilities["workspace/peekDocuments"]
// TODO: Check if client supports LSP 3.18's workspace/textDocumentContent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this check should be in place before we merge the PR

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you address this TODO? I don’t like having TODOs in the codebase without an associated issue because in practice they never get fixed.

Copy link
Member Author

@fwcd fwcd Sep 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think we have to revert this for now. Once the request is upstreamed, we can relax this condition to support clients that don't explicitly declare it as an experimental capability.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've re-added this and added a short remark to the PR description for how this check has to be updated once we wish to support the upstream client capability.

{
let expansionURIs = try macroExpansionReferenceDocumentURLs.map {
return DocumentURI(try $0.url)
Expand Down
2 changes: 1 addition & 1 deletion Sources/SourceKitLSP/Swift/ReferenceDocumentURL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Foundation
import LanguageServerProtocol

/// A Reference Document is a document whose url scheme is `sourcekit-lsp:` and whose content can only be retrieved
/// using `GetReferenceDocumentRequest`. The enum represents a specific type of reference document and its
/// using `TextDocumentContentRequest`. The enum represents a specific type of reference document and its
/// associated value represents the data necessary to generate the document's contents and its url
///
/// The `url` will be of the form: `sourcekit-lsp://<document-type>/<display-name>?<parameters>`
Expand Down
6 changes: 3 additions & 3 deletions Sources/SourceKitLSP/Swift/SwiftLanguageService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1002,13 +1002,13 @@ extension SwiftLanguageService {
return nil
}

package func getReferenceDocument(_ req: GetReferenceDocumentRequest) async throws -> GetReferenceDocumentResponse {
package func textDocumentContent(_ req: TextDocumentContentRequest) async throws -> TextDocumentContentResponse {
let referenceDocumentURL = try ReferenceDocumentURL(from: req.uri)

switch referenceDocumentURL {
case let .macroExpansion(data):
return GetReferenceDocumentResponse(
content: try await macroExpansionManager.macroExpansion(for: data)
return TextDocumentContentResponse(
text: try await macroExpansionManager.macroExpansion(for: data)
)
}
}
Expand Down
Loading