priority -> yieldTo for drop/paste API proposals (#189881)

Move await from `priority` for drop/paste API proposals

For #179430, #30066

Switching to use `yieldTo` instead of `priority` to let an extension de-rank itself in the list of edits. `priority` was an arbitrary number while `yieldTo` gives more control over how the ranking takes place
This commit is contained in:
Matt Bierner
2023-08-07 18:32:03 -07:00
committed by GitHub
parent 4f66a0c2c1
commit 39df243d21
14 changed files with 124 additions and 88 deletions
+3 -14
View File
@@ -15,6 +15,7 @@ enum MimeType {
png = 'image/png', png = 'image/png',
tiff = 'image/tiff', tiff = 'image/tiff',
webp = 'image/webp', webp = 'image/webp',
plain = 'text/plain',
uriList = 'text/uri-list', uriList = 'text/uri-list',
} }
@@ -49,8 +50,6 @@ class DropOrPasteEditProvider implements vscode.DocumentPasteEditProvider, vscod
private readonly id = 'insertAttachment'; private readonly id = 'insertAttachment';
private readonly defaultPriority = 5;
async provideDocumentPasteEdits( async provideDocumentPasteEdits(
document: vscode.TextDocument, document: vscode.TextDocument,
_ranges: readonly vscode.Range[], _ranges: readonly vscode.Range[],
@@ -68,7 +67,7 @@ class DropOrPasteEditProvider implements vscode.DocumentPasteEditProvider, vscod
} }
const pasteEdit = new vscode.DocumentPasteEdit(insert.insertText, this.id, vscode.l10n.t('Insert Image as Attachment')); const pasteEdit = new vscode.DocumentPasteEdit(insert.insertText, this.id, vscode.l10n.t('Insert Image as Attachment'));
pasteEdit.priority = this.getPastePriority(dataTransfer); pasteEdit.yieldTo = [{ mimeType: MimeType.plain }];
pasteEdit.additionalEdit = insert.additionalEdit; pasteEdit.additionalEdit = insert.additionalEdit;
return pasteEdit; return pasteEdit;
} }
@@ -86,22 +85,12 @@ class DropOrPasteEditProvider implements vscode.DocumentPasteEditProvider, vscod
const dropEdit = new vscode.DocumentDropEdit(insert.insertText); const dropEdit = new vscode.DocumentDropEdit(insert.insertText);
dropEdit.id = this.id; dropEdit.id = this.id;
dropEdit.priority = this.defaultPriority; dropEdit.yieldTo = [{ mimeType: MimeType.plain }];
dropEdit.additionalEdit = insert.additionalEdit; dropEdit.additionalEdit = insert.additionalEdit;
dropEdit.label = vscode.l10n.t('Insert Image as Attachment'); dropEdit.label = vscode.l10n.t('Insert Image as Attachment');
return dropEdit; return dropEdit;
} }
private getPastePriority(dataTransfer: vscode.DataTransfer): number {
if (dataTransfer.get('text/plain')) {
// Deprioritize in favor of normal text content
return -5;
}
// Otherwise boost priority so attachments are preferred
return this.defaultPriority;
}
private async createInsertImageAttachmentEdit( private async createInsertImageAttachmentEdit(
document: vscode.TextDocument, document: vscode.TextDocument,
dataTransfer: vscode.DataTransfer, dataTransfer: vscode.DataTransfer,
@@ -11,6 +11,11 @@ class PasteEditProvider implements vscode.DocumentPasteEditProvider {
private readonly _id = 'insertLink'; private readonly _id = 'insertLink';
private readonly _yieldTo = [
{ mimeType: 'text/plain' },
{ extensionId: 'vscode.ipynb', editId: 'insertAttachment' },
];
async provideDocumentPasteEdits( async provideDocumentPasteEdits(
document: vscode.TextDocument, document: vscode.TextDocument,
ranges: readonly vscode.Range[], ranges: readonly vscode.Range[],
@@ -32,7 +37,8 @@ class PasteEditProvider implements vscode.DocumentPasteEditProvider {
if (!urlList) { if (!urlList) {
return; return;
} }
const pasteUrlSetting = await getPasteUrlAsFormattedLinkSetting(document);
const pasteUrlSetting = getPasteUrlAsFormattedLinkSetting(document);
const pasteEdit = await createEditAddingLinksForUriList(document, ranges, urlList, false, pasteUrlSetting === PasteUrlAsFormattedLink.Smart, token); const pasteEdit = await createEditAddingLinksForUriList(document, ranges, urlList, false, pasteUrlSetting === PasteUrlAsFormattedLink.Smart, token);
if (!pasteEdit) { if (!pasteEdit) {
return; return;
@@ -40,7 +46,7 @@ class PasteEditProvider implements vscode.DocumentPasteEditProvider {
uriEdit.label = pasteEdit.label; uriEdit.label = pasteEdit.label;
uriEdit.additionalEdit = pasteEdit.additionalEdits; uriEdit.additionalEdit = pasteEdit.additionalEdits;
uriEdit.priority = this._getPriority(dataTransfer); uriEdit.yieldTo = this._yieldTo;
return uriEdit; return uriEdit;
} }
@@ -61,17 +67,9 @@ class PasteEditProvider implements vscode.DocumentPasteEditProvider {
const pasteEdit = new vscode.DocumentPasteEdit(edit.snippet, this._id, edit.label); const pasteEdit = new vscode.DocumentPasteEdit(edit.snippet, this._id, edit.label);
pasteEdit.additionalEdit = edit.additionalEdits; pasteEdit.additionalEdit = edit.additionalEdits;
pasteEdit.priority = this._getPriority(dataTransfer); pasteEdit.yieldTo = this._yieldTo;
return pasteEdit; return pasteEdit;
} }
private _getPriority(dataTransfer: vscode.DataTransfer): number {
if (dataTransfer.get('text/plain')) {
// Deprioritize in favor of normal text content
return -10;
}
return 0;
}
} }
export function registerPasteSupport(selector: vscode.DocumentSelector,) { export function registerPasteSupport(selector: vscode.DocumentSelector,) {
@@ -5,60 +5,44 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { createEditAddingLinksForUriList, getPasteUrlAsFormattedLinkSetting, PasteUrlAsFormattedLink, validateLink } from './shared'; import { createEditAddingLinksForUriList, getPasteUrlAsFormattedLinkSetting, PasteUrlAsFormattedLink, validateLink } from './shared';
const textPlainMime = 'text/plain';
class PasteLinkEditProvider implements vscode.DocumentPasteEditProvider { class PasteLinkEditProvider implements vscode.DocumentPasteEditProvider {
readonly id = 'insertMarkdownLink'; readonly id = 'insertMarkdownLink';
async provideDocumentPasteEdits( async provideDocumentPasteEdits(
document: vscode.TextDocument, document: vscode.TextDocument,
ranges: readonly vscode.Range[], ranges: readonly vscode.Range[],
dataTransfer: vscode.DataTransfer, dataTransfer: vscode.DataTransfer,
token: vscode.CancellationToken, token: vscode.CancellationToken,
): Promise<vscode.DocumentPasteEdit | undefined> { ): Promise<vscode.DocumentPasteEdit | undefined> {
const pasteUrlSetting = await getPasteUrlAsFormattedLinkSetting(document); const pasteUrlSetting = getPasteUrlAsFormattedLinkSetting(document);
if (pasteUrlSetting === PasteUrlAsFormattedLink.Never) { if (pasteUrlSetting === PasteUrlAsFormattedLink.Never) {
return; return;
} }
const item = dataTransfer.get('text/plain'); const item = dataTransfer.get(textPlainMime);
const urlList = await item?.asString(); const urlList = await item?.asString();
if (token.isCancellationRequested || !urlList || !validateLink(urlList).isValid) {
if (urlList === undefined) {
return; return;
} }
if (!validateLink(urlList).isValid) {
return;
}
const uriEdit = new vscode.DocumentPasteEdit('', this.id, '');
if (!urlList) {
return undefined;
}
const pasteEdit = await createEditAddingLinksForUriList(document, ranges, validateLink(urlList).cleanedUrlList, true, pasteUrlSetting === PasteUrlAsFormattedLink.Smart, token); const pasteEdit = await createEditAddingLinksForUriList(document, ranges, validateLink(urlList).cleanedUrlList, true, pasteUrlSetting === PasteUrlAsFormattedLink.Smart, token);
if (!pasteEdit) { if (!pasteEdit) {
return; return;
} }
uriEdit.label = pasteEdit.label; const edit = new vscode.DocumentPasteEdit('', this.id, pasteEdit.label);
uriEdit.additionalEdit = pasteEdit.additionalEdits; edit.additionalEdit = pasteEdit.additionalEdits;
uriEdit.priority = this._getPriority(pasteEdit.markdownLink); edit.yieldTo = pasteEdit.markdownLink ? undefined : [{ mimeType: textPlainMime }];
return uriEdit; return edit;
}
private _getPriority(pasteAsMarkdownLink: boolean): number {
if (!pasteAsMarkdownLink) {
// Deprioritize in favor of default paste
return -10;
}
return 0;
} }
} }
export function registerLinkPasteSupport(selector: vscode.DocumentSelector,) { export function registerLinkPasteSupport(selector: vscode.DocumentSelector,) {
return vscode.languages.registerDocumentPasteEditProvider(selector, new PasteLinkEditProvider(), { return vscode.languages.registerDocumentPasteEditProvider(selector, new PasteLinkEditProvider(), {
pasteMimeTypes: [ pasteMimeTypes: [textPlainMime]
'text/plain',
]
}); });
} }
@@ -9,8 +9,14 @@ import { Schemes } from '../../util/schemes';
class MarkdownImageDropProvider implements vscode.DocumentDropEditProvider { class MarkdownImageDropProvider implements vscode.DocumentDropEditProvider {
private readonly _id = 'insertLink'; private readonly _id = 'insertLink';
private readonly _yieldTo = [
{ mimeType: 'text/plain' },
{ extensionId: 'vscode.ipynb', editId: 'insertAttachment' },
];
async provideDocumentDropEdits(document: vscode.TextDocument, _position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.DocumentDropEdit | undefined> { async provideDocumentDropEdits(document: vscode.TextDocument, _position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.DocumentDropEdit | undefined> {
const enabled = vscode.workspace.getConfiguration('markdown', document).get('editor.drop.enabled', true); const enabled = vscode.workspace.getConfiguration('markdown', document).get('editor.drop.enabled', true);
if (!enabled) { if (!enabled) {
@@ -42,6 +48,7 @@ class MarkdownImageDropProvider implements vscode.DocumentDropEditProvider {
const edit = new vscode.DocumentDropEdit(snippet.snippet); const edit = new vscode.DocumentDropEdit(snippet.snippet);
edit.id = this._id; edit.id = this._id;
edit.label = snippet.label; edit.label = snippet.label;
edit.yieldTo = this._yieldTo;
return edit; return edit;
} }
@@ -64,6 +71,7 @@ class MarkdownImageDropProvider implements vscode.DocumentDropEditProvider {
edit.id = this._id; edit.id = this._id;
edit.label = filesEdit.label; edit.label = filesEdit.label;
edit.additionalEdit = filesEdit.additionalEdits; edit.additionalEdit = filesEdit.additionalEdits;
edit.yieldTo = this._yieldTo;
return edit; return edit;
} }
} }
@@ -83,7 +83,7 @@ export enum PasteUrlAsFormattedLink {
Never = 'never' Never = 'never'
} }
export async function getPasteUrlAsFormattedLinkSetting(document: vscode.TextDocument): Promise<PasteUrlAsFormattedLink> { export function getPasteUrlAsFormattedLinkSetting(document: vscode.TextDocument): PasteUrlAsFormattedLink {
return vscode.workspace.getConfiguration('markdown', document).get<PasteUrlAsFormattedLink>('editor.pasteUrlAsFormattedLink.enabled', PasteUrlAsFormattedLink.Smart); return vscode.workspace.getConfiguration('markdown', document).get<PasteUrlAsFormattedLink>('editor.pasteUrlAsFormattedLink.enabled', PasteUrlAsFormattedLink.Smart);
} }
+9 -2
View File
@@ -805,7 +805,8 @@ export interface DocumentPasteEdit {
readonly id: string; readonly id: string;
readonly label: string; readonly label: string;
readonly detail: string; readonly detail: string;
readonly priority: number; readonly handledMimeType?: string;
readonly yieldTo?: readonly DropYieldTo[];
insertText: string | { readonly snippet: string }; insertText: string | { readonly snippet: string };
additionalEdit?: WorkspaceEdit; additionalEdit?: WorkspaceEdit;
} }
@@ -2008,13 +2009,19 @@ export enum ExternalUriOpenerPriority {
Preferred = 3, Preferred = 3,
} }
/**
* @internal
*/
export type DropYieldTo = { readonly editId: string } | { readonly mimeType: string };
/** /**
* @internal * @internal
*/ */
export interface DocumentOnDropEdit { export interface DocumentOnDropEdit {
readonly id: string; readonly id: string;
readonly label: string; readonly label: string;
readonly priority: number; readonly handledMimeType?: string;
readonly yieldTo?: readonly DropYieldTo[];
insertText: string | { readonly snippet: string }; insertText: string | { readonly snippet: string };
additionalEdit?: WorkspaceEdit; additionalEdit?: WorkspaceEdit;
} }
@@ -24,7 +24,7 @@ import { Handler, IEditorContribution, PastePayload } from 'vs/editor/common/edi
import { DocumentPasteEdit, DocumentPasteEditProvider } from 'vs/editor/common/languages'; import { DocumentPasteEdit, DocumentPasteEditProvider } from 'vs/editor/common/languages';
import { ITextModel } from 'vs/editor/common/model'; import { ITextModel } from 'vs/editor/common/model';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures'; import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { createCombinedWorkspaceEdit } from 'vs/editor/contrib/dropOrPasteInto/browser/edit'; import { createCombinedWorkspaceEdit, sortEditsByYieldTo } from 'vs/editor/contrib/dropOrPasteInto/browser/edit';
import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState'; import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';
import { InlineProgressManager } from 'vs/editor/contrib/inlineProgress/browser/inlineProgress'; import { InlineProgressManager } from 'vs/editor/contrib/inlineProgress/browser/inlineProgress';
import { localize } from 'vs/nls'; import { localize } from 'vs/nls';
@@ -432,7 +432,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
} }
private async getPasteEdits(providers: readonly DocumentPasteEditProvider[], dataTransfer: VSDataTransfer, model: ITextModel, selections: readonly Selection[], token: CancellationToken): Promise<DocumentPasteEdit[]> { private async getPasteEdits(providers: readonly DocumentPasteEditProvider[], dataTransfer: VSDataTransfer, model: ITextModel, selections: readonly Selection[], token: CancellationToken): Promise<DocumentPasteEdit[]> {
const result = await raceCancellation( const results = await raceCancellation(
Promise.all(providers.map(provider => { Promise.all(providers.map(provider => {
try { try {
return provider.provideDocumentPasteEdits?.(model, selections, dataTransfer, token); return provider.provideDocumentPasteEdits?.(model, selections, dataTransfer, token);
@@ -440,10 +440,11 @@ export class CopyPasteController extends Disposable implements IEditorContributi
console.error(err); console.error(err);
return undefined; return undefined;
} }
})).then(coalesce), })),
token); token);
result?.sort((a, b) => b.priority - a.priority); const edits = coalesce(results ?? []);
return result ?? []; sortEditsByYieldTo(edits);
return edits;
} }
private async applyDefaultPasteHandler(dataTransfer: VSDataTransfer, metadata: CopyMetadata | undefined, token: CancellationToken) { private async applyDefaultPasteHandler(dataTransfer: VSDataTransfer, metadata: CopyMetadata | undefined, token: CancellationToken) {
@@ -29,12 +29,12 @@ abstract class SimplePasteAndDropProvider implements DocumentOnDropEditProvider,
async provideDocumentPasteEdits(_model: ITextModel, _ranges: readonly IRange[], dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined> { async provideDocumentPasteEdits(_model: ITextModel, _ranges: readonly IRange[], dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined> {
const edit = await this.getEdit(dataTransfer, token); const edit = await this.getEdit(dataTransfer, token);
return edit ? { id: this.id, insertText: edit.insertText, label: edit.label, detail: edit.detail, priority: edit.priority } : undefined; return edit ? { id: this.id, insertText: edit.insertText, label: edit.label, detail: edit.detail, handledMimeType: edit.handledMimeType, yieldTo: edit.yieldTo } : undefined;
} }
async provideDocumentOnDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<DocumentOnDropEdit | undefined> { async provideDocumentOnDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<DocumentOnDropEdit | undefined> {
const edit = await this.getEdit(dataTransfer, token); const edit = await this.getEdit(dataTransfer, token);
return edit ? { id: this.id, insertText: edit.insertText, label: edit.label, priority: edit.priority } : undefined; return edit ? { id: this.id, insertText: edit.insertText, label: edit.label, handledMimeType: edit.handledMimeType, yieldTo: edit.yieldTo } : undefined;
} }
protected abstract getEdit(dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined>; protected abstract getEdit(dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined>;
@@ -46,7 +46,7 @@ class DefaultTextProvider extends SimplePasteAndDropProvider {
readonly dropMimeTypes = [Mimes.text]; readonly dropMimeTypes = [Mimes.text];
readonly pasteMimeTypes = [Mimes.text]; readonly pasteMimeTypes = [Mimes.text];
protected async getEdit(dataTransfer: IReadonlyVSDataTransfer, _token: CancellationToken) { protected async getEdit(dataTransfer: IReadonlyVSDataTransfer, _token: CancellationToken): Promise<DocumentPasteEdit | undefined> {
const textEntry = dataTransfer.get(Mimes.text); const textEntry = dataTransfer.get(Mimes.text);
if (!textEntry) { if (!textEntry) {
return; return;
@@ -61,7 +61,7 @@ class DefaultTextProvider extends SimplePasteAndDropProvider {
const insertText = await textEntry.asString(); const insertText = await textEntry.asString();
return { return {
id: this.id, id: this.id,
priority: 0, handledMimeType: Mimes.text,
label: localize('text.label', "Insert Plain Text"), label: localize('text.label', "Insert Plain Text"),
detail: builtInLabel, detail: builtInLabel,
insertText insertText
@@ -75,7 +75,7 @@ class PathProvider extends SimplePasteAndDropProvider {
readonly dropMimeTypes = [Mimes.uriList]; readonly dropMimeTypes = [Mimes.uriList];
readonly pasteMimeTypes = [Mimes.uriList]; readonly pasteMimeTypes = [Mimes.uriList];
protected async getEdit(dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken) { protected async getEdit(dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined> {
const entries = await extractUriList(dataTransfer); const entries = await extractUriList(dataTransfer);
if (!entries.length || token.isCancellationRequested) { if (!entries.length || token.isCancellationRequested) {
return; return;
@@ -108,7 +108,7 @@ class PathProvider extends SimplePasteAndDropProvider {
return { return {
id: this.id, id: this.id,
priority: 0, handledMimeType: Mimes.uriList,
insertText, insertText,
label, label,
detail: builtInLabel, detail: builtInLabel,
@@ -128,7 +128,7 @@ class RelativePathProvider extends SimplePasteAndDropProvider {
super(); super();
} }
protected async getEdit(dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken) { protected async getEdit(dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined> {
const entries = await extractUriList(dataTransfer); const entries = await extractUriList(dataTransfer);
if (!entries.length || token.isCancellationRequested) { if (!entries.length || token.isCancellationRequested) {
return; return;
@@ -145,7 +145,7 @@ class RelativePathProvider extends SimplePasteAndDropProvider {
return { return {
id: this.id, id: this.id,
priority: 0, handledMimeType: Mimes.uriList,
insertText: relativeUris.join(' '), insertText: relativeUris.join(' '),
label: entries.length > 1 label: entries.length > 1
? localize('defaultDropProvider.uriList.relativePaths', "Insert Relative Paths") ? localize('defaultDropProvider.uriList.relativePaths', "Insert Relative Paths")
@@ -25,6 +25,7 @@ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { LocalSelectionTransfer } from 'vs/platform/dnd/browser/dnd'; import { LocalSelectionTransfer } from 'vs/platform/dnd/browser/dnd';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { PostEditWidgetManager } from './postEditWidget'; import { PostEditWidgetManager } from './postEditWidget';
import { sortEditsByYieldTo as sortEditsByYieldTo } from './edit';
export const changeDropTypeCommandId = 'editor.changeDropType'; export const changeDropTypeCommandId = 'editor.changeDropType';
@@ -128,7 +129,7 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
return provider.provideDocumentOnDropEdits(model, position, dataTransfer, tokenSource.token); return provider.provideDocumentOnDropEdits(model, position, dataTransfer, tokenSource.token);
})), tokenSource.token); })), tokenSource.token);
const edits = coalesce(results ?? []); const edits = coalesce(results ?? []);
edits.sort((a, b) => b.priority - a.priority); sortEditsByYieldTo(edits);
return edits; return edits;
} }
@@ -5,7 +5,7 @@
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService'; import { ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService';
import { WorkspaceEdit } from 'vs/editor/common/languages'; import { DropYieldTo, WorkspaceEdit } from 'vs/editor/common/languages';
import { Range } from 'vs/editor/common/core/range'; import { Range } from 'vs/editor/common/core/range';
export interface DropOrPasteEdit { export interface DropOrPasteEdit {
@@ -27,3 +27,26 @@ export function createCombinedWorkspaceEdit(uri: URI, ranges: readonly Range[],
] ]
}; };
} }
export function sortEditsByYieldTo<T extends {
readonly id: string;
readonly handledMimeType?: string;
readonly yieldTo?: readonly DropYieldTo[];
}>(edits: T[]): void {
function yieldsTo(yTo: DropYieldTo, other: T): boolean {
return ('editId' in yTo && yTo.editId === other.id)
|| ('mimeType' in yTo && yTo.mimeType === other.handledMimeType);
}
edits.sort((a, b) => {
if (a.yieldTo?.some(yTo => yieldsTo(yTo, b))) {
return 1;
}
if (b.yieldTo?.some(yTo => yieldsTo(yTo, a))) {
return -1;
}
return 0;
});
}
@@ -1897,7 +1897,7 @@ export interface IPasteEditDto {
id: string; id: string;
label: string; label: string;
detail: string; detail: string;
priority: number; yieldTo?: readonly languages.DropYieldTo[];
insertText: string | { snippet: string }; insertText: string | { snippet: string };
additionalEdit?: IWorkspaceEditDto; additionalEdit?: IWorkspaceEditDto;
} }
@@ -1909,7 +1909,7 @@ export interface IDocumentDropEditProviderMetadata {
export interface IDocumentOnDropEditDto { export interface IDocumentOnDropEditDto {
id: string; id: string;
label: string; label: string;
priority: number; yieldTo?: readonly languages.DropYieldTo[];
insertText: string | { snippet: string }; insertText: string | { snippet: string };
additionalEdit?: IWorkspaceEditDto; additionalEdit?: IWorkspaceEditDto;
} }
@@ -553,14 +553,20 @@ class DocumentPasteEditProvider {
} }
return { return {
id: edit.id ? this._extension.identifier.value + '.' + edit.id : this._extension.identifier.value, id: edit.id ? this.toInternalId(this._extension.identifier.value, edit.id) : this._extension.identifier.value,
label: edit.label ?? localize('defaultPasteLabel', "Paste using '{0}' extension", this._extension.displayName || this._extension.name), label: edit.label ?? localize('defaultPasteLabel', "Paste using '{0}' extension", this._extension.displayName || this._extension.name),
detail: this._extension.displayName || this._extension.name, detail: this._extension.displayName || this._extension.name,
priority: edit.priority ?? 0, yieldTo: edit.yieldTo?.map(yTo => {
return 'mimeType' in yTo ? yTo : { editId: this.toInternalId(yTo.extensionId, yTo.editId) };
}),
insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value }, insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined) : undefined, additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined) : undefined,
}; };
} }
private toInternalId(extId: string, editId: string): string {
return extId + '.' + editId;
}
} }
class DocumentFormattingAdapter { class DocumentFormattingAdapter {
@@ -1799,13 +1805,19 @@ class DocumentOnDropEditAdapter {
return undefined; return undefined;
} }
return { return {
id: edit.id ? this._extension.identifier.value + '.' + edit.id : this._extension.identifier.value, id: edit.id ? this.toInternalId(this._extension.identifier.value, edit.id) : this._extension.identifier.value,
label: edit.label ?? localize('defaultDropLabel', "Drop using '{0}' extension", this._extension.displayName || this._extension.name), label: edit.label ?? localize('defaultDropLabel', "Drop using '{0}' extension", this._extension.displayName || this._extension.name),
priority: edit.priority ?? 0, yieldTo: edit.yieldTo?.map(yTo => {
return 'mimeType' in yTo ? yTo : { editId: this.toInternalId(yTo.extensionId, yTo.editId) };
}),
insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value }, insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined) : undefined, additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined) : undefined,
}; };
} }
private toInternalId(extId: string, editId: string): string {
return extId + '.' + editId;
}
} }
type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
+5 -4
View File
@@ -57,11 +57,12 @@ declare module 'vscode' {
label: string; label: string;
/** /**
* The relative priority of this edit. Higher priority items are shown first in the UI. * Controls the ordering or multiple paste edits. If this provider yield to edits, it will be shown lower in the list.
*
* Defaults to `0`.
*/ */
priority?: number; yieldTo?: ReadonlyArray<
| { readonly extensionId: string; readonly editId: string }
| { readonly mimeType: string }
>;
/** /**
* The text or snippet to insert at the pasted locations. * The text or snippet to insert at the pasted locations.
+19 -7
View File
@@ -12,20 +12,32 @@ declare module 'vscode' {
* Identifies the type of edit. * Identifies the type of edit.
* *
* This id should be unique within the extension but does not need to be unique across extensions. * This id should be unique within the extension but does not need to be unique across extensions.
*
* TODO: Should this live on the provider instead? That way we could call just the provider we want (however it would
* prevent extending providers in the future to allow returning multiple edits)
*/ */
id?: string; id?: string;
/**
* The relative priority of this edit. Higher priority items are shown first in the UI.
*
* Defaults to `0`.
*/
priority?: number;
/** /**
* Human readable label that describes the edit. * Human readable label that describes the edit.
*/ */
label?: string; label?: string;
/**
* The mime type from the {@link DataTransfer} that this edit applies.
*
* TODO: Should this be taken from `dropMimeTypes` instead?
*/
handledMimeType?: string;
/**
* Controls the ordering or multiple paste edits. If this provider yield to edits, it will be shown lower in the list.
*/
yieldTo?: ReadonlyArray<
// TODO: what about built-in providers?
| { readonly extensionId: string; readonly editId: string }
| { readonly mimeType: string }
>;
} }
export interface DocumentDropEditProviderMetadata { export interface DocumentDropEditProviderMetadata {