From 3ada59c963e6bb029da1a626927cdbb8c51d4bf0 Mon Sep 17 00:00:00 2001 From: Roland Grunberg Date: Tue, 9 Apr 2024 16:30:00 -0400 Subject: [PATCH] Adjust the document paste handling provider. - provideDocumentPasteEdits API was updated in VS Code 1.88.0 Signed-off-by: Roland Grunberg --- src/pasteEventHandler.ts | 17 ++-- vscode.proposed.documentPaste.d.ts | 153 ++++++++++++++++++++++++++--- 2 files changed, 147 insertions(+), 23 deletions(-) diff --git a/src/pasteEventHandler.ts b/src/pasteEventHandler.ts index cff25bd4f..6f6648830 100644 --- a/src/pasteEventHandler.ts +++ b/src/pasteEventHandler.ts @@ -1,4 +1,4 @@ -import { CancellationToken, commands, DataTransfer, DocumentPasteEdit as VDocumentPasteEdit, DocumentPasteEditProvider, DocumentPasteProviderMetadata, ExtensionContext, languages, Range, TextDocument, window } from "vscode"; +import { CancellationToken, commands, DataTransfer, DocumentPasteEdit as VDocumentPasteEdit, DocumentPasteEditProvider, DocumentPasteProviderMetadata, ExtensionContext, languages, Range, TextDocument, window, DocumentPasteEditContext, ProviderResult, DocumentPasteEdit } from "vscode"; import { FormattingOptions, Location, WorkspaceEdit as PWorkspaceEdit } from "vscode-languageclient"; import { LanguageClient } from "vscode-languageclient/node"; import { Commands } from "./commands"; @@ -6,7 +6,8 @@ import { JAVA_SELECTOR } from "./standardLanguageClient"; const TEXT_MIMETYPE: string = "text/plain"; const MIMETYPES: DocumentPasteProviderMetadata = { - pasteMimeTypes: [TEXT_MIMETYPE] + pasteMimeTypes: [TEXT_MIMETYPE], + providedPasteEditKinds: [] }; /** @@ -61,7 +62,7 @@ class PasteEditProvider implements DocumentPasteEditProvider { } } - async provideDocumentPasteEdits(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): Promise { + async provideDocumentPasteEdits?(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, context: DocumentPasteEditContext, token: CancellationToken): Promise { const insertText: string = await dataTransfer.get(TEXT_MIMETYPE).asString(); @@ -92,10 +93,12 @@ class PasteEditProvider implements DocumentPasteEditProvider { try { const pasteResponse: PDocumentPasteEdit = await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.HANDLE_PASTE_EVENT, JSON.stringify(pasteEventParams)); if (pasteResponse) { - return { - insertText: pasteResponse.insertText, - additionalEdit: pasteResponse.additionalEdit ? await this.languageClient.protocol2CodeConverter.asWorkspaceEdit(pasteResponse.additionalEdit) : undefined - } as VDocumentPasteEdit; + return [ + { + insertText: pasteResponse.insertText, + additionalEdit: pasteResponse.additionalEdit ? await this.languageClient.protocol2CodeConverter.asWorkspaceEdit(pasteResponse.additionalEdit) : undefined + } + ] as DocumentPasteEdit[]; } } catch (e) { // Do nothing diff --git a/vscode.proposed.documentPaste.d.ts b/vscode.proposed.documentPaste.d.ts index 57ea908f8..627c8dcc1 100644 --- a/vscode.proposed.documentPaste.d.ts +++ b/vscode.proposed.documentPaste.d.ts @@ -8,42 +8,107 @@ declare module 'vscode' { // https://github.com/microsoft/vscode/issues/30066/ /** - * Provider invoked when the user copies and pastes code. + * The reason why paste edits were requested. */ - interface DocumentPasteEditProvider { + export enum DocumentPasteTriggerKind { + /** + * Pasting was requested as part of a normal paste operation. + */ + Automatic = 0, + + /** + * Pasting was requested by the user with the `paste as` command. + */ + PasteAs = 1, + } + + /** + * Additional information about the paste operation. + */ + + export interface DocumentPasteEditContext { + /** + * Requested kind of paste edits to return. + */ + readonly only: DocumentPasteEditKind | undefined; + + /** + * The reason why paste edits were requested. + */ + readonly triggerKind: DocumentPasteTriggerKind; + } + + /** + * Provider invoked when the user copies or pastes in a {@linkcode TextDocument}. + */ + interface DocumentPasteEditProvider { /** * Optional method invoked after the user copies text in a file. * - * During {@link prepareDocumentPaste}, an extension can compute metadata that is attached to - * a {@link DataTransfer} and is passed back to the provider in {@link provideDocumentPasteEdits}. + * This allows the provider to attach copy metadata to the {@link DataTransfer} + * which is then passed back to providers in {@linkcode provideDocumentPasteEdits}. + * + * Note that currently any changes to the {@linkcode DataTransfer} are isolated to the current editor session. + * This means that added metadata cannot be seen by other applications. * * @param document Document where the copy took place. - * @param ranges Ranges being copied in the `document`. - * @param dataTransfer The data transfer associated with the copy. You can store additional values on this for later use in {@link provideDocumentPasteEdits}. + * @param ranges Ranges being copied in {@linkcode document}. + * @param dataTransfer The data transfer associated with the copy. You can store additional values on this for later use in {@linkcode provideDocumentPasteEdits}. + * This object is only valid for the duration of this method. * @param token A cancellation token. + * + * @return Optional thenable that resolves when all changes to the `dataTransfer` are complete. */ prepareDocumentPaste?(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): void | Thenable; /** * Invoked before the user pastes into a document. * - * In this method, extensions can return a workspace edit that replaces the standard pasting behavior. + * Returned edits can replace the standard pasting behavior. * * @param document Document being pasted into - * @param ranges Currently selected ranges in the document. - * @param dataTransfer The data transfer associated with the paste. + * @param ranges Range in the {@linkcode document} to paste into. + * @param dataTransfer The {@link DataTransfer data transfer} associated with the paste. This object is only valid for the duration of the paste operation. + * @param context Additional context for the paste. + * @param token A cancellation token. + * + * @return Set of potential {@link DocumentPasteEdit edits} that apply the paste. Return `undefined` to use standard pasting. + */ + provideDocumentPasteEdits?(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, context: DocumentPasteEditContext, token: CancellationToken): ProviderResult; + + /** + * Optional method which fills in the {@linkcode DocumentPasteEdit.additionalEdit} before the edit is applied. + * + * This is called once per edit and should be used if generating the complete edit may take a long time. + * Resolve can only be used to change {@link DocumentPasteEdit.additionalEdit}. + * + * @param pasteEdit The {@linkcode DocumentPasteEdit} to resolve. * @param token A cancellation token. * - * @return Optional workspace edit that applies the paste. Return undefined to use standard pasting. + * @returns The resolved paste edit or a thenable that resolves to such. It is OK to return the given + * `pasteEdit`. If no result is returned, the given `pasteEdit` is used. */ - provideDocumentPasteEdits(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): ProviderResult; + resolveDocumentPasteEdit?(pasteEdit: T, token: CancellationToken): ProviderResult; } /** - * An operation applied on paste + * An edit applied on paste. */ class DocumentPasteEdit { + + /** + * Human readable label that describes the edit. + */ + title: string; + + /** + * {@link DocumentPasteEditKind Kind} of the edit. + * + * Used to identify specific types of edits. + */ + kind: DocumentPasteEditKind; + /** * The text or snippet to insert at the pasted locations. */ @@ -55,21 +120,77 @@ declare module 'vscode' { additionalEdit?: WorkspaceEdit; /** + * Controls the ordering of paste edits provided by multiple providers. + * + * If this edit yields to another, it will be shown lower in the list of paste edit. + */ + yieldTo?: readonly DocumentPasteEditKind[]; + + /** + * Create a new paste edit. + * * @param insertText The text or snippet to insert at the pasted locations. + * @param title Human readable label that describes the edit. + * @param kind {@link DocumentPasteEditKind Kind} of the edit. */ - constructor(insertText: string | SnippetString); + constructor(insertText: string | SnippetString, title: string, kind: DocumentPasteEditKind); + } + + + /** + * TODO: Share with code action kind? + */ + class DocumentPasteEditKind { + static readonly Empty: DocumentPasteEditKind; + + // TODO: Add `Text` any others? + + private constructor(value: string); + + readonly value: string; + + append(...parts: string[]): CodeActionKind; + intersects(other: CodeActionKind): boolean; + contains(other: CodeActionKind): boolean; } interface DocumentPasteProviderMetadata { /** - * Mime types that `provideDocumentPasteEdits` should be invoked for. + * List of {@link DocumentPasteEditKind kinds} that the provider may return in {@linkcode DocumentPasteEditProvider.provideDocumentPasteEdits provideDocumentPasteEdits}. * - * Use the special `files` mimetype to indicate the provider should be invoked if any files are present in the `DataTransfer`. + * The provider will only be invoked when one of these kinds is being requested. For normal pasting, all providers will be invoked. + */ + readonly providedPasteEditKinds: readonly DocumentPasteEditKind[]; + + /** + * Mime types that {@linkcode DocumentPasteEditProvider.prepareDocumentPaste prepareDocumentPaste} may add on copy. */ - readonly pasteMimeTypes: readonly string[]; + readonly copyMimeTypes?: readonly string[]; + + /** + * Mime types that {@linkcode DocumentPasteEditProvider.provideDocumentPasteEdits provideDocumentPasteEdits} should be invoked for. + * + * This can either be an exact mime type such as `image/png`, or a wildcard pattern such as `image/*`. + * + * Use `text/uri-list` for resources dropped from the explorer or other tree views in the workbench. + * + * Use `files` to indicate that the provider should be invoked if any {@link DataTransferFile files} are present in the {@linkcode DataTransfer}. + * Note that {@linkcode DataTransferFile} entries are only created when dropping content from outside the editor, such as + * from the operating system. + */ + readonly pasteMimeTypes?: readonly string[]; } namespace languages { + /** + * Registers a new {@linkcode DocumentPasteEditProvider}. + * + * @param selector A selector that defines the documents this provider applies to. + * @param provider A paste editor provider. + * @param metadata Additional metadata about the provider. + * + * @returns A {@link Disposable} that unregisters this provider when disposed of. + */ export function registerDocumentPasteEditProvider(selector: DocumentSelector, provider: DocumentPasteEditProvider, metadata: DocumentPasteProviderMetadata): Disposable; } }