diff --git a/extensions/ipynb/src/notebookImagePaste.ts b/extensions/ipynb/src/notebookImagePaste.ts index 263a610da85..7ea63e7026a 100644 --- a/extensions/ipynb/src/notebookImagePaste.ts +++ b/extensions/ipynb/src/notebookImagePaste.ts @@ -68,7 +68,7 @@ class DropOrPasteEditProvider implements vscode.DocumentPasteEditProvider, vscod } const pasteEdit = new vscode.DocumentPasteEdit(insert.insertText, vscode.l10n.t('Insert Image as Attachment'), DropOrPasteEditProvider.kind); - pasteEdit.yieldTo = [{ mimeType: MimeType.plain }]; + pasteEdit.yieldTo = [vscode.DocumentPasteEditKind.Empty.append('text')]; pasteEdit.additionalEdit = insert.additionalEdit; return [pasteEdit]; } @@ -85,7 +85,7 @@ class DropOrPasteEditProvider implements vscode.DocumentPasteEditProvider, vscod } const dropEdit = new vscode.DocumentDropEdit(insert.insertText); - dropEdit.yieldTo = [{ mimeType: MimeType.plain }]; + dropEdit.yieldTo = [vscode.DocumentPasteEditKind.Empty.append('text')]; dropEdit.additionalEdit = insert.additionalEdit; dropEdit.title = vscode.l10n.t('Insert Image as Attachment'); return dropEdit; diff --git a/extensions/markdown-language-features/src/languageFeatures/copyFiles/dropOrPasteResource.ts b/extensions/markdown-language-features/src/languageFeatures/copyFiles/dropOrPasteResource.ts index 20ea5a17743..821164c6ed2 100644 --- a/extensions/markdown-language-features/src/languageFeatures/copyFiles/dropOrPasteResource.ts +++ b/extensions/markdown-language-features/src/languageFeatures/copyFiles/dropOrPasteResource.ts @@ -31,8 +31,8 @@ class ResourcePasteOrDropProvider implements vscode.DocumentPasteEditProvider, v ]; private readonly _yieldTo = [ - { mimeType: 'text/plain' }, - { kind: vscode.DocumentPasteEditKind.Empty.append('markdown', 'image', 'attachment') }, + vscode.DocumentPasteEditKind.Empty.append('text'), + vscode.DocumentPasteEditKind.Empty.append('markdown', 'image', 'attachment'), ]; public async provideDocumentDropEdits( diff --git a/extensions/markdown-language-features/src/languageFeatures/copyFiles/pasteUrlProvider.ts b/extensions/markdown-language-features/src/languageFeatures/copyFiles/pasteUrlProvider.ts index 193112e9630..dbbc2a1a231 100644 --- a/extensions/markdown-language-features/src/languageFeatures/copyFiles/pasteUrlProvider.ts +++ b/extensions/markdown-language-features/src/languageFeatures/copyFiles/pasteUrlProvider.ts @@ -71,7 +71,7 @@ class PasteUrlEditProvider implements vscode.DocumentPasteEditProvider { pasteEdit.additionalEdit = workspaceEdit; if (!(await shouldInsertMarkdownLinkByDefault(this._parser, document, pasteUrlSetting, ranges, token))) { - pasteEdit.yieldTo = [{ mimeType: Mime.textPlain }]; + pasteEdit.yieldTo = [vscode.DocumentPasteEditKind.Empty.append('text')]; } return [pasteEdit]; diff --git a/src/vs/base/common/dataTransfer.ts b/src/vs/base/common/dataTransfer.ts index bed42389897..9c9ac45640b 100644 --- a/src/vs/base/common/dataTransfer.ts +++ b/src/vs/base/common/dataTransfer.ts @@ -50,6 +50,7 @@ export interface IReadonlyVSDataTransfer extends Iterable 1 ? localize('defaultDropProvider.uriList.relativePaths', "Insert Relative Paths") : localize('defaultDropProvider.uriList.relativePath', "Insert Relative Path"), - kind: new HierarchicalKind(this.kind), + kind: this.kind, }; } } diff --git a/src/vs/editor/contrib/dropOrPasteInto/browser/edit.ts b/src/vs/editor/contrib/dropOrPasteInto/browser/edit.ts index 252c1863cba..81cc89436cf 100644 --- a/src/vs/editor/contrib/dropOrPasteInto/browser/edit.ts +++ b/src/vs/editor/contrib/dropOrPasteInto/browser/edit.ts @@ -42,7 +42,7 @@ export function sortEditsByYieldTo { test('Yielded to edit should get sorted after target', () => { const edits: DocumentOnDropEdit[] = [ - createTestEdit('a', { yieldTo: [{ kind: 'b' }] }), + createTestEdit('a', { yieldTo: [{ kind: new HierarchicalKind('b') }] }), createTestEdit('b'), ]; assert.deepStrictEqual(sortEditsByYieldTo(edits).map(x => x.kind?.value), ['b', 'a']); @@ -37,8 +37,8 @@ suite('sortEditsByYieldTo', () => { test('Should handle chain of yield to', () => { { const edits: DocumentOnDropEdit[] = [ - createTestEdit('c', { yieldTo: [{ kind: 'a' }] }), - createTestEdit('a', { yieldTo: [{ kind: 'b' }] }), + createTestEdit('c', { yieldTo: [{ kind: new HierarchicalKind('a') }] }), + createTestEdit('a', { yieldTo: [{ kind: new HierarchicalKind('b') }] }), createTestEdit('b'), ]; @@ -46,8 +46,8 @@ suite('sortEditsByYieldTo', () => { } { const edits: DocumentOnDropEdit[] = [ - createTestEdit('a', { yieldTo: [{ kind: 'b' }] }), - createTestEdit('c', { yieldTo: [{ kind: 'a' }] }), + createTestEdit('a', { yieldTo: [{ kind: new HierarchicalKind('b') }] }), + createTestEdit('c', { yieldTo: [{ kind: new HierarchicalKind('a') }] }), createTestEdit('b'), ]; @@ -57,8 +57,8 @@ suite('sortEditsByYieldTo', () => { test(`Should not reorder when yield to isn't used`, () => { const edits: DocumentOnDropEdit[] = [ - createTestEdit('c', { yieldTo: [{ kind: 'x' }] }), - createTestEdit('a', { yieldTo: [{ kind: 'y' }] }), + createTestEdit('c', { yieldTo: [{ kind: new HierarchicalKind('x') }] }), + createTestEdit('a', { yieldTo: [{ kind: new HierarchicalKind('y') }] }), createTestEdit('b'), ]; diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index a41310b7ce8..d89eecf9a3f 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -1053,6 +1053,7 @@ class MainThreadPasteEditProvider implements languages.DocumentPasteEditProvider return { ...edit, kind: edit.kind ? new HierarchicalKind(edit.kind.value) : new HierarchicalKind(''), + yieldTo: edit.yieldTo?.map(x => ({ kind: new HierarchicalKind(x) })), additionalEdit: edit.additionalEdit ? reviveWorkspaceEditDto(edit.additionalEdit, this._uriIdentService, dataId => this.resolveFileData(request.id, dataId)) : undefined, }; }), @@ -1112,6 +1113,7 @@ class MainThreadDocumentOnDropEditProvider implements languages.DocumentOnDropEd return edits.map(edit => { return { ...edit, + yieldTo: edit.yieldTo?.map(x => ({ kind: new HierarchicalKind(x) })), kind: edit.kind ? new HierarchicalKind(edit.kind) : undefined, additionalEdit: reviveWorkspaceEditDto(edit.additionalEdit, this._uriIdentService, dataId => this.resolveDocumentOnDropFileData(request.id, dataId)), }; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 9055bfa9aea..13be2bb8b60 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -2080,7 +2080,7 @@ export interface IPasteEditDto { kind: { value: string } | undefined; insertText: string | { snippet: string }; additionalEdit?: IWorkspaceEditDto; - yieldTo?: readonly languages.DropYieldTo[]; + yieldTo?: readonly string[]; } export interface IDocumentDropEditProviderMetadata { @@ -2092,7 +2092,7 @@ export interface IDocumentOnDropEditDto { kind: string | undefined; insertText: string | { snippet: string }; additionalEdit?: IWorkspaceEditDto; - yieldTo?: readonly languages.DropYieldTo[]; + yieldTo?: readonly string[]; } export interface ExtHostLanguageFeaturesShape { diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 19f6cd063c4..5b688307db2 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -590,14 +590,11 @@ class DocumentPasteEditProvider { const cacheId = this._cache.add(edits); - return edits.map((edit, i) => ({ + return edits.map((edit, i): extHostProtocol.IPasteEditDto => ({ _cacheId: [cacheId, i], title: edit.title ?? localize('defaultPasteLabel', "Paste using '{0}' extension", this._extension.displayName || this._extension.name), kind: edit.kind, - detail: this._extension.displayName || this._extension.name, - yieldTo: edit.yieldTo?.map(yTo => { - return 'mimeType' in yTo ? yTo : { kind: yTo.kind.value }; - }), + yieldTo: edit.yieldTo?.map(x => x.value), insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value }, additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined) : undefined, })); @@ -1982,15 +1979,10 @@ class DocumentOnDropEditAdapter { return undefined; } - return asArray(edits).map(edit => ({ + return asArray(edits).map((edit): extHostProtocol.IDocumentOnDropEditDto => ({ title: edit.title ?? localize('defaultDropLabel', "Drop using '{0}' extension", this._extension.displayName || this._extension.name), kind: edit.kind?.value, - yieldTo: edit.yieldTo?.map(yTo => { - if ('mimeType' in yTo) { - return yTo; - } - return { kind: yTo.kind.value }; - }), + yieldTo: edit.yieldTo?.map(x => x.value), insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value }, additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined) : undefined, })); diff --git a/src/vscode-dts/vscode.proposed.documentPaste.d.ts b/src/vscode-dts/vscode.proposed.documentPaste.d.ts index 4abe25ad160..627c8dcc1cb 100644 --- a/src/vscode-dts/vscode.proposed.documentPaste.d.ts +++ b/src/vscode-dts/vscode.proposed.documentPaste.d.ts @@ -17,7 +17,7 @@ declare module 'vscode' { Automatic = 0, /** - * Pasting was requested by the user with the 'paste as' command. + * Pasting was requested by the user with the `paste as` command. */ PasteAs = 1, } @@ -27,6 +27,9 @@ declare module 'vscode' { */ export interface DocumentPasteEditContext { + /** + * Requested kind of paste edits to return. + */ readonly only: DocumentPasteEditKind | undefined; /** @@ -36,19 +39,22 @@ declare module 'vscode' { } /** - * Provider invoked when the user copies and pastes code. + * 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 `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. * @@ -62,8 +68,8 @@ declare module 'vscode' { * 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. * @@ -74,19 +80,20 @@ declare module 'vscode' { /** * Optional method which fills in the {@linkcode DocumentPasteEdit.additionalEdit} before the edit is applied. * - * This should be used if generating the `additionalEdit` may take a long time. + * 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. * * @returns The resolved paste edit or a thenable that resolves to such. It is OK to return the given - * `item`. When no result is returned, the given `item` will be used. + * `pasteEdit`. If no result is returned, the given `pasteEdit` is used. */ resolveDocumentPasteEdit?(pasteEdit: T, token: CancellationToken): ProviderResult; } /** - * An edit applied on paste + * An edit applied on paste. */ class DocumentPasteEdit { @@ -112,17 +119,12 @@ declare module 'vscode' { */ additionalEdit?: WorkspaceEdit; - /** - * List of mime types that this edit handles. - */ - handledMimeTypes?: readonly string[]; - /** * 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?: ReadonlyArray<{ readonly kind: DocumentPasteEditKind } | { readonly mimeType: string }>; + yieldTo?: readonly DocumentPasteEditKind[]; /** * Create a new paste edit. @@ -140,6 +142,9 @@ declare module 'vscode' { */ class DocumentPasteEditKind { static readonly Empty: DocumentPasteEditKind; + + // TODO: Add `Text` any others? + private constructor(value: string); readonly value: string; @@ -150,8 +155,12 @@ declare module 'vscode' { } interface DocumentPasteProviderMetadata { - // TODO - readonly providedPasteEditKinds?: readonly DocumentPasteEditKind[]; + /** + * List of {@link DocumentPasteEditKind kinds} that the provider may return in {@linkcode DocumentPasteEditProvider.provideDocumentPasteEdits provideDocumentPasteEdits}. + * + * 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. @@ -173,6 +182,15 @@ declare module 'vscode' { } 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; } } diff --git a/src/vscode-dts/vscode.proposed.dropMetadata.d.ts b/src/vscode-dts/vscode.proposed.dropMetadata.d.ts index c851f13f9df..63631c4ac7b 100644 --- a/src/vscode-dts/vscode.proposed.dropMetadata.d.ts +++ b/src/vscode-dts/vscode.proposed.dropMetadata.d.ts @@ -10,8 +10,8 @@ declare module 'vscode' { /** * TODO: - * - Add ctor(insertText: string | SnippetString, title?: string, kind?: DocumentPasteEditKind); - * - Update provide to return multiple edits + * - Add ctor(insertText: string | SnippetString, title?: string, kind?: DocumentPasteEditKind); Can't be done as this is an extension to an existing class + * - Update provider to return multiple edits */ export interface DocumentDropEdit { @@ -39,7 +39,7 @@ declare module 'vscode' { /** * Controls the ordering or multiple paste edits. If this provider yield to edits, it will be shown lower in the list. */ - yieldTo?: ReadonlyArray<{ readonly kind: DocumentPasteEditKind } | { readonly mimeType: string }>; + yieldTo?: ReadonlyArray; } export interface DocumentDropEditProviderMetadata {