From 8c2aab90532bbdf63017b130ec641748bde7f769 Mon Sep 17 00:00:00 2001 From: Lokesh T R Date: Fri, 28 Jun 2024 23:13:52 +0530 Subject: [PATCH] Handle custom `PeekDocumentsRequest` to show macro expansions in a peeked editor --- src/sourcekit-lsp/LanguageClientManager.ts | 10 ++++++ src/sourcekit-lsp/lspExtensions.ts | 39 ++++++++++++++++++++++ src/sourcekit-lsp/peekDocuments.ts | 37 ++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 src/sourcekit-lsp/peekDocuments.ts diff --git a/src/sourcekit-lsp/LanguageClientManager.ts b/src/sourcekit-lsp/LanguageClientManager.ts index a47ce2cb7..a2eff1e45 100644 --- a/src/sourcekit-lsp/LanguageClientManager.ts +++ b/src/sourcekit-lsp/LanguageClientManager.ts @@ -20,6 +20,7 @@ import { isPathInsidePath, swiftRuntimeEnv } from "../utilities/utilities"; import { Version } from "../utilities/version"; import { FolderEvent, WorkspaceContext } from "../WorkspaceContext"; import { activateLegacyInlayHints } from "./inlayHints"; +import { activatePeekDocuments } from "./peekDocuments"; import { FolderContext } from "../FolderContext"; import { LanguageClient } from "vscode-languageclient/node"; import { ArgumentFilter, BuildFlags } from "../toolchain/BuildFlags"; @@ -108,6 +109,7 @@ export class LanguageClientManager { private languageClient: langclient.LanguageClient | null | undefined; private cancellationToken?: vscode.CancellationTokenSource; private legacyInlayHints?: vscode.Disposable; + private peekDocuments?: vscode.Disposable; private restartedPromise?: Promise; private currentWorkspaceFolder?: vscode.Uri; private waitingOnRestartCount: number; @@ -244,6 +246,7 @@ export class LanguageClientManager { this.cancellationToken?.cancel(); this.cancellationToken?.dispose(); this.legacyInlayHints?.dispose(); + this.peekDocuments?.dispose(); this.subscriptions.forEach(item => item.dispose()); this.languageClient?.stop(); this.namedOutputChannels.forEach(channel => channel.dispose()); @@ -392,6 +395,8 @@ export class LanguageClientManager { this.currentWorkspaceFolder = workspaceFolder?.uri; this.legacyInlayHints?.dispose(); this.legacyInlayHints = undefined; + this.peekDocuments?.dispose(); + this.peekDocuments = undefined; if (client) { this.cancellationToken?.cancel(); this.cancellationToken?.dispose(); @@ -559,6 +564,9 @@ export class LanguageClientManager { })(), }, errorHandler: new SourceKitLSPErrorHandler(5), + initializationOptions: { + "workspace/peekDocuments": true, // workaround for client capability to handle `PeekDocumentsRequest` + }, }; return new langclient.LanguageClient( @@ -604,6 +612,8 @@ export class LanguageClientManager { if (this.workspaceContext.swiftVersion.isLessThan(new Version(5, 7, 0))) { this.legacyInlayHints = activateLegacyInlayHints(client); } + + this.peekDocuments = activatePeekDocuments(client); }) .catch(reason => { this.workspaceContext.outputChannel.log(`${reason}`); diff --git a/src/sourcekit-lsp/lspExtensions.ts b/src/sourcekit-lsp/lspExtensions.ts index 364278376..6837a22f2 100644 --- a/src/sourcekit-lsp/lspExtensions.ts +++ b/src/sourcekit-lsp/lspExtensions.ts @@ -14,9 +14,48 @@ import * as ls from "vscode-languageserver-protocol"; import * as langclient from "vscode-languageclient/node"; +import * as vscode from "vscode"; // Definitions for non-standard requests used by sourcekit-lsp +// Peek Documents +export interface PeekDocumentsParams { + /** + * The `DocumentUri` of the text document in which to show the "peeked" editor + */ + uri: langclient.DocumentUri; + + /** + * The `Position` in the given text document in which to show the "peeked editor" + */ + position: vscode.Position; + + /** + * An array `DocumentUri` of the documents to appear inside the "peeked" editor + */ + locations: langclient.DocumentUri[]; +} + +/** + * Response to indicate the `success` of the `PeekDocumentsRequest` + */ +export interface PeekDocumentsResult { + success: boolean; +} + +/** + * Request from the server to the client to show the given documents in a "peeked" editor. + * + * This request is handled by the client to show the given documents in a "peeked" editor (i.e. inline with / inside the editor canvas). + * + * It requires the experimental client capability `"workspace/peekDocuments"` to use. + */ +export const PeekDocumentsRequest = new langclient.RequestType< + PeekDocumentsParams, + PeekDocumentsResult, + unknown +>("workspace/peekDocuments"); + // Inlay Hints (pre Swift 5.6) export interface LegacyInlayHintsParams { /** diff --git a/src/sourcekit-lsp/peekDocuments.ts b/src/sourcekit-lsp/peekDocuments.ts new file mode 100644 index 000000000..4771c7f3f --- /dev/null +++ b/src/sourcekit-lsp/peekDocuments.ts @@ -0,0 +1,37 @@ +import * as vscode from "vscode"; +import * as langclient from "vscode-languageclient/node"; +import { PeekDocumentsParams, PeekDocumentsRequest } from "./lspExtensions"; + +export function activatePeekDocuments(client: langclient.LanguageClient): vscode.Disposable { + const peekDocuments = client.onRequest( + PeekDocumentsRequest.method, + async (params: PeekDocumentsParams) => { + const locations = params.locations.map(uri => { + const location = new vscode.Location( + vscode.Uri.from({ + scheme: "file", + path: new URL(uri).pathname, + }), + new vscode.Position(0, 0) + ); + + return location; + }); + + await vscode.commands.executeCommand( + "editor.action.peekLocations", + vscode.Uri.from({ + scheme: "file", + path: new URL(params.uri).pathname, + }), + new vscode.Position(params.position.line, params.position.character), + locations, + "peek" + ); + + return { success: true }; + } + ); + + return peekDocuments; +}