Skip to content

Commit f49c429

Browse files
committed
Allow macro expansions to be viewed through GetReferenceDocumentRequest instead of storing in temporary files
1 parent e4cb1bd commit f49c429

17 files changed

+707
-288
lines changed

Documentation/LSP Extensions.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,3 +473,28 @@ export interface PeekDocumentsResult {
473473
success: boolean;
474474
}
475475
```
476+
477+
## `workspace/getReferenceDocument`
478+
479+
Request from the client to the server asking for contents of a URI having a custom scheme.
480+
For example: "sourcekit-lsp:"
481+
482+
- params: `GetReferenceDocumentParams`
483+
484+
- result: `GetReferenceDocumentResponse`
485+
486+
```ts
487+
export interface GetReferenceDocumentParams {
488+
/**
489+
* The `DocumentUri` of the custom scheme url for which content is required
490+
*/
491+
uri: DocumentUri;
492+
}
493+
494+
/**
495+
* Response containing `content` of `GetReferenceDocumentRequest`
496+
*/
497+
export interface GetReferenceDocumentResult {
498+
content: string;
499+
}
500+
```

Sources/LanguageServerProtocol/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ add_library(LanguageServerProtocol STATIC
5555
Requests/ExecuteCommandRequest.swift
5656
Requests/FoldingRangeRequest.swift
5757
Requests/FormattingRequests.swift
58+
Requests/GetReferenceDocumentRequest.swift
5859
Requests/HoverRequest.swift
5960
Requests/ImplementationRequest.swift
6061
Requests/IndexedRenameRequest.swift

Sources/LanguageServerProtocol/Messages.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public let builtinRequests: [_RequestType.Type] = [
4848
DocumentTestsRequest.self,
4949
ExecuteCommandRequest.self,
5050
FoldingRangeRequest.self,
51+
GetReferenceDocumentRequest.self,
5152
HoverRequest.self,
5253
ImplementationRequest.self,
5354
InitializeRequest.self,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 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 from the client to the server asking for contents of a URI having a custom scheme **(LSP Extension)**
14+
/// For example: "sourcekit-lsp:"
15+
///
16+
/// - Parameters:
17+
/// - uri: The `DocumentUri` of the custom scheme url for which content is required
18+
///
19+
/// - Returns: `GetReferenceDocumentResponse` which contains the `content` to be displayed.
20+
///
21+
/// ### LSP Extension
22+
///
23+
/// This request is an extension to LSP supported by SourceKit-LSP.
24+
public struct GetReferenceDocumentRequest: RequestType {
25+
public static let method: String = "workspace/getReferenceDocument"
26+
public typealias Response = GetReferenceDocumentResponse
27+
28+
public var uri: DocumentURI
29+
30+
public init(uri: DocumentURI) {
31+
self.uri = uri
32+
}
33+
}
34+
35+
/// Response containing `content` of `GetReferenceDocumentRequest`
36+
public struct GetReferenceDocumentResponse: ResponseType {
37+
public var content: String
38+
39+
public init(content: String) {
40+
self.content = content
41+
}
42+
}

Sources/SKSupport/LineTable.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import LSPLogging
14+
1415
#if canImport(os)
1516
import os
1617
#endif

Sources/SourceKitLSP/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,12 @@ target_sources(SourceKitLSP PRIVATE
4747
Swift/ExpandMacroCommand.swift
4848
Swift/FoldingRange.swift
4949
Swift/MacroExpansion.swift
50+
Swift/MacroExpansionReferenceDocument.swift
5051
Swift/OpenInterface.swift
5152
Swift/RefactoringResponse.swift
5253
Swift/RefactoringEdit.swift
5354
Swift/RefactorCommand.swift
55+
Swift/ReferenceDocument.swift
5456
Swift/RelatedIdentifiers.swift
5557
Swift/RewriteSourceKitPlaceholders.swift
5658
Swift/SemanticRefactorCommand.swift

Sources/SourceKitLSP/Clang/ClangLanguageService.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,10 @@ extension ClangLanguageService {
647647
func executeCommand(_ req: ExecuteCommandRequest) async throws -> LSPAny? {
648648
return try await forwardRequestToClangd(req)
649649
}
650+
651+
func getReferenceDocument(_ req: GetReferenceDocumentRequest) async throws -> GetReferenceDocumentResponse {
652+
throw ResponseError.unknown("unsupported method")
653+
}
650654
}
651655

652656
/// Clang build settings derived from a `FileBuildSettingsChange`.

Sources/SourceKitLSP/LanguageService.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ public protocol LanguageService: AnyObject, Sendable {
250250

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

253+
func getReferenceDocument(_ req: GetReferenceDocumentRequest) async throws -> GetReferenceDocumentResponse
254+
253255
/// Perform a syntactic scan of the file at the given URI for test cases and test classes.
254256
///
255257
/// This is used as a fallback to show the test cases in a file if the index for a given file is not up-to-date.

Sources/SourceKitLSP/Rename.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,7 @@ extension SourceKitLSPServer {
687687
guard let workspace = await workspaceForDocument(uri: uri) else {
688688
throw ResponseError.workspaceNotOpen(uri)
689689
}
690-
guard let primaryFileLanguageService = workspace.documentService.value[uri] else {
690+
guard let primaryFileLanguageService = workspace.documentService(for: uri) else {
691691
return nil
692692
}
693693

Sources/SourceKitLSP/SourceKitLSPServer.swift

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ public actor SourceKitLSPServer {
357357

358358
// This should be created as soon as we receive an open call, even if the document
359359
// isn't yet ready.
360-
guard let languageService = workspace.documentService.value[doc] else {
360+
guard let languageService = workspace.documentService(for: doc) else {
361361
return
362362
}
363363

@@ -377,7 +377,7 @@ public actor SourceKitLSPServer {
377377
guard let workspace = await self.workspaceForDocument(uri: request.textDocument.uri) else {
378378
throw ResponseError.workspaceNotOpen(request.textDocument.uri)
379379
}
380-
guard let languageService = workspace.documentService.value[doc] else {
380+
guard let languageService = workspace.documentService(for: doc) else {
381381
throw ResponseError.unknown("No language service for '\(request.textDocument.uri)' found")
382382
}
383383
return try await requestHandler(request, workspace, languageService)
@@ -400,7 +400,7 @@ public actor SourceKitLSPServer {
400400
guard let workspace = await self.workspaceForDocument(uri: documentUri) else {
401401
continue
402402
}
403-
guard workspace.documentService.value[documentUri] === languageService else {
403+
guard workspace.documentService(for: documentUri) === languageService else {
404404
continue
405405
}
406406
guard let snapshot = try? self.documentManager.latestSnapshot(documentUri) else {
@@ -518,7 +518,7 @@ public actor SourceKitLSPServer {
518518
_ language: Language,
519519
in workspace: Workspace
520520
) async -> LanguageService? {
521-
if let service = workspace.documentService.value[uri] {
521+
if let service = workspace.documentService(for: uri) {
522522
return service
523523
}
524524

@@ -731,6 +731,8 @@ extension SourceKitLSPServer: MessageHandler {
731731
await request.reply { try await executeCommand(request.params) }
732732
case let request as RequestAndReply<FoldingRangeRequest>:
733733
await self.handleRequest(for: request, requestHandler: self.foldingRange)
734+
case let request as RequestAndReply<GetReferenceDocumentRequest>:
735+
await request.reply { try await getReferenceDocument(request.params) }
734736
case let request as RequestAndReply<HoverRequest>:
735737
await self.handleRequest(for: request, requestHandler: self.hover)
736738
case let request as RequestAndReply<ImplementationRequest>:
@@ -802,7 +804,7 @@ extension SourceKitLSPServer: BuildSystemDelegate {
802804
continue
803805
}
804806

805-
guard let service = await self.workspaceForDocument(uri: uri)?.documentService.value[uri] else {
807+
guard let service = await self.workspaceForDocument(uri: uri)?.documentService(for: uri) else {
806808
continue
807809
}
808810

@@ -826,7 +828,7 @@ extension SourceKitLSPServer: BuildSystemDelegate {
826828
}
827829
for uri in self.affectedOpenDocumentsForChangeSet(changedFilesForWorkspace, self.documentManager) {
828830
logger.log("Dependencies updated for opened file \(uri.forLogging)")
829-
if let service = workspace.documentService.value[uri] {
831+
if let service = workspace.documentService(for: uri) {
830832
await service.documentDependenciesUpdated(uri)
831833
}
832834
}
@@ -961,15 +963,26 @@ extension SourceKitLSPServer {
961963
//
962964
// The below is a workaround for the vscode-swift extension since it cannot set client capabilities.
963965
// It passes "workspace/peekDocuments" through the `initializationOptions`.
966+
//
967+
// Similarly, for "workspace/getReferenceDocument".
964968
var clientCapabilities = req.capabilities
965-
if case .dictionary(let initializationOptions) = req.initializationOptions,
966-
let peekDocuments = initializationOptions["workspace/peekDocuments"]
967-
{
968-
if case .dictionary(var experimentalCapabilities) = clientCapabilities.experimental {
969-
experimentalCapabilities["workspace/peekDocuments"] = peekDocuments
970-
clientCapabilities.experimental = .dictionary(experimentalCapabilities)
971-
} else {
972-
clientCapabilities.experimental = .dictionary(["workspace/peekDocuments": peekDocuments])
969+
if case .dictionary(let initializationOptions) = req.initializationOptions {
970+
if let peekDocuments = initializationOptions["workspace/peekDocuments"] {
971+
if case .dictionary(var experimentalCapabilities) = clientCapabilities.experimental {
972+
experimentalCapabilities["workspace/peekDocuments"] = peekDocuments
973+
clientCapabilities.experimental = .dictionary(experimentalCapabilities)
974+
} else {
975+
clientCapabilities.experimental = .dictionary(["workspace/peekDocuments": peekDocuments])
976+
}
977+
}
978+
979+
if let getReferenceDocument = initializationOptions["workspace/getReferenceDocument"] {
980+
if case .dictionary(var experimentalCapabilities) = clientCapabilities.experimental {
981+
experimentalCapabilities["workspace/getReferenceDocument"] = getReferenceDocument
982+
clientCapabilities.experimental = .dictionary(experimentalCapabilities)
983+
} else {
984+
clientCapabilities.experimental = .dictionary(["workspace/getReferenceDocument": getReferenceDocument])
985+
}
973986
}
974987
}
975988

@@ -1121,6 +1134,7 @@ extension SourceKitLSPServer {
11211134
"workspace/tests": .dictionary(["version": .int(2)]),
11221135
"textDocument/tests": .dictionary(["version": .int(2)]),
11231136
"workspace/triggerReindex": .dictionary(["version": .int(1)]),
1137+
"workspace/getReferenceDocument": .dictionary(["version": .int(1)]),
11241138
])
11251139
)
11261140
}
@@ -1320,7 +1334,7 @@ extension SourceKitLSPServer {
13201334
)
13211335
return
13221336
}
1323-
await workspace.documentService.value[uri]?.reopenDocument(notification)
1337+
await workspace.documentService(for: uri)?.reopenDocument(notification)
13241338
}
13251339

13261340
func closeDocument(_ notification: DidCloseTextDocumentNotification, workspace: Workspace) async {
@@ -1334,7 +1348,7 @@ extension SourceKitLSPServer {
13341348

13351349
await workspace.buildSystemManager.unregisterForChangeNotifications(for: uri)
13361350

1337-
await workspace.documentService.value[uri]?.closeDocument(notification)
1351+
await workspace.documentService(for: uri)?.closeDocument(notification)
13381352
}
13391353

13401354
func changeDocument(_ notification: DidChangeTextDocumentNotification) async {
@@ -1360,7 +1374,7 @@ extension SourceKitLSPServer {
13601374
// Already logged failure
13611375
return
13621376
}
1363-
await workspace.documentService.value[uri]?.changeDocument(
1377+
await workspace.documentService(for: uri)?.changeDocument(
13641378
notification,
13651379
preEditSnapshot: preEditSnapshot,
13661380
postEditSnapshot: postEditSnapshot,
@@ -1623,7 +1637,7 @@ extension SourceKitLSPServer {
16231637
guard let workspace = await workspaceForDocument(uri: uri) else {
16241638
throw ResponseError.workspaceNotOpen(uri)
16251639
}
1626-
guard let languageService = workspace.documentService.value[uri] else {
1640+
guard let languageService = workspace.documentService(for: uri) else {
16271641
return nil
16281642
}
16291643

@@ -1634,6 +1648,21 @@ extension SourceKitLSPServer {
16341648
return try await languageService.executeCommand(executeCommand)
16351649
}
16361650

1651+
func getReferenceDocument(_ req: GetReferenceDocumentRequest) async throws -> GetReferenceDocumentResponse {
1652+
let referenceDocument = try req.uri.referenceDocument()
1653+
let sourceFileURI = referenceDocument.sourceDocument()
1654+
1655+
guard let workspace = await workspaceForDocument(uri: sourceFileURI) else {
1656+
throw ResponseError.workspaceNotOpen(sourceFileURI)
1657+
}
1658+
1659+
guard let languageService = workspace.documentService(for: sourceFileURI) else {
1660+
throw ResponseError.unknown("No Language Service for URI: \(sourceFileURI)")
1661+
}
1662+
1663+
return try await languageService.getReferenceDocument(req)
1664+
}
1665+
16371666
func codeAction(
16381667
_ req: CodeActionRequest,
16391668
workspace: Workspace,

0 commit comments

Comments
 (0)