Add paste as command (#181959)

For #30066

This command shows a quick pick that lets you select how to paste content
This commit is contained in:
Matt Bierner 2023-05-10 06:17:42 -07:00 committed by GitHub
parent 4182ec739b
commit ca51a4b04c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 223 additions and 33 deletions

View File

@ -45,6 +45,7 @@ function getImageMimeType(uri: vscode.Uri): string | undefined {
return imageExtToMime.get(extname(uri.fsPath).toLowerCase());
}
const id = 'insertAttachment';
class CopyPasteEditProvider implements vscode.DocumentPasteEditProvider {
async provideDocumentPasteEdits(
@ -63,7 +64,7 @@ class CopyPasteEditProvider implements vscode.DocumentPasteEditProvider {
return;
}
const pasteEdit = new vscode.DocumentPasteEdit(insert.insertText, vscode.l10n.t('Insert Image as Attachment'));
const pasteEdit = new vscode.DocumentPasteEdit(insert.insertText, id, vscode.l10n.t('Insert Image as Attachment'));
pasteEdit.additionalEdit = insert.additionalEdit;
return pasteEdit;
}
@ -83,6 +84,7 @@ class DropEditProvider implements vscode.DocumentDropEditProvider {
}
const dropEdit = new vscode.DocumentDropEdit(insert.insertText);
dropEdit.id = id;
dropEdit.additionalEdit = insert.additionalEdit;
dropEdit.label = vscode.l10n.t('Insert Image as Attachment');
return dropEdit;
@ -302,7 +304,6 @@ export function notebookImagePasteSetup(): vscode.Disposable {
],
}),
vscode.languages.registerDocumentDropEditProvider(JUPYTER_NOTEBOOK_MARKDOWN_SELECTOR, new DropEditProvider(), {
id: 'imageAttachment',
dropMimeTypes: [
...Object.values(imageExtToMime),
MimeType.uriList,

View File

@ -19,6 +19,8 @@ const supportedImageMimes = new Set([
class PasteEditProvider implements vscode.DocumentPasteEditProvider {
private readonly _id = 'insertLink';
async provideDocumentPasteEdits(
document: vscode.TextDocument,
_ranges: readonly vscode.Range[],
@ -36,7 +38,7 @@ class PasteEditProvider implements vscode.DocumentPasteEditProvider {
}
const snippet = await tryGetUriListSnippet(document, dataTransfer, token);
return snippet ? new vscode.DocumentPasteEdit(snippet.snippet, snippet.label) : undefined;
return snippet ? new vscode.DocumentPasteEdit(snippet.snippet, this._id, snippet.label) : undefined;
}
private async _makeCreateImagePasteEdit(document: vscode.TextDocument, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.DocumentPasteEdit | undefined> {
@ -87,7 +89,7 @@ class PasteEditProvider implements vscode.DocumentPasteEditProvider {
return;
}
const pasteEdit = new vscode.DocumentPasteEdit(snippet.snippet, snippet.label);
const pasteEdit = new vscode.DocumentPasteEdit(snippet.snippet, '', snippet.label);
pasteEdit.additionalEdit = workspaceEdit;
return pasteEdit;
}

View File

@ -43,11 +43,11 @@ export function registerDropIntoEditorSupport(selector: vscode.DocumentSelector)
}
const edit = new vscode.DocumentDropEdit(snippet.snippet);
edit.id = 'insertLink';
edit.label = snippet.label;
return edit;
}
}, {
id: 'insertLink',
dropMimeTypes: [
'text/uri-list'
]

View File

@ -783,7 +783,9 @@ export interface CodeActionProvider {
* @internal
*/
export interface DocumentPasteEdit {
readonly id: string;
readonly label: string;
readonly detail: string;
insertText: string | { readonly snippet: string };
additionalEdit?: WorkspaceEdit;
}
@ -1944,8 +1946,8 @@ export enum ExternalUriOpenerPriority {
* @internal
*/
export interface DocumentOnDropEdit {
readonly id: string;
readonly label: string;
insertText: string | { readonly snippet: string };
additionalEdit?: WorkspaceEdit;
}
@ -1954,7 +1956,6 @@ export interface DocumentOnDropEdit {
* @internal
*/
export interface DocumentOnDropEditProvider {
readonly id: string;
readonly dropMimeTypes?: readonly string[];
provideDocumentOnDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): ProviderResult<DocumentOnDropEdit>;

View File

@ -5,14 +5,17 @@
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorCommand, EditorContributionInstantiation, ServicesAccessor, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { EditorAction, EditorCommand, EditorContributionInstantiation, ServicesAccessor, registerEditorAction, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { registerEditorFeature } from 'vs/editor/common/editorFeatures';
import { CopyPasteController, changePasteTypeCommandId, pasteWidgetVisibleCtx } from 'vs/editor/contrib/dropOrPasteInto/browser/copyPasteController';
import { DefaultPasteProvidersFeature } from 'vs/editor/contrib/dropOrPasteInto/browser/defaultProviders';
import * as nls from 'vs/nls';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
registerEditorContribution(CopyPasteController.ID, CopyPasteController, EditorContributionInstantiation.Eager); // eager because it listens to events on the container dom node of the editor
registerEditorFeature(DefaultPasteProvidersFeature);
registerEditorCommand(new class extends EditorCommand {
constructor() {
super({
@ -26,8 +29,37 @@ registerEditorCommand(new class extends EditorCommand {
}
public override runEditorCommand(_accessor: ServicesAccessor | null, editor: ICodeEditor, _args: any) {
CopyPasteController.get(editor)?.changePasteType();
return CopyPasteController.get(editor)?.changePasteType();
}
});
registerEditorFeature(DefaultPasteProvidersFeature);
registerEditorAction(class extends EditorAction {
constructor() {
super({
id: 'editor.action.pasteAs',
label: nls.localize('pasteAs', "Paste As..."),
alias: 'Paste As...',
precondition: undefined,
description: {
description: 'Paste as',
args: [{
name: 'args',
schema: {
type: 'object',
properties: {
'id': {
type: 'string',
description: nls.localize('pasteAs.id', "The id of the paste edit to try applying. If not provided, the editor will show a picker."),
}
},
}
}]
}
});
}
public override run(_accessor: ServicesAccessor, editor: ICodeEditor, args: any) {
const id = typeof args?.id === 'string' ? args.id : undefined;
return CopyPasteController.get(editor)?.pasteAs(id);
}
});

View File

@ -14,6 +14,7 @@ import * as platform from 'vs/base/common/platform';
import { generateUuid } from 'vs/base/common/uuid';
import { toExternalVSDataTransfer, toVSDataTransfer } from 'vs/editor/browser/dnd';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { IRange, Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
@ -21,12 +22,15 @@ import { Handler, IEditorContribution, PastePayload } from 'vs/editor/common/edi
import { DocumentPasteEdit, DocumentPasteEditProvider } from 'vs/editor/common/languages';
import { ITextModel } from 'vs/editor/common/model';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { createCombinedWorkspaceEdit } from 'vs/editor/contrib/dropOrPasteInto/browser/edit';
import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';
import { InlineProgressManager } from 'vs/editor/contrib/inlineProgress/browser/inlineProgress';
import { localize } from 'vs/nls';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { PostEditWidgetManager } from './postEditWidget';
export const changePasteTypeCommandId = 'editor.changePasteType';
@ -58,6 +62,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
};
private _currentPasteOperation?: CancelablePromise<void>;
private _pasteAsActionContext?: { readonly preferredId: string | undefined };
private readonly _pasteProgressManager: InlineProgressManager;
private readonly _postPasteWidgetManager: PostEditWidgetManager;
@ -65,8 +70,11 @@ export class CopyPasteController extends Disposable implements IEditorContributi
constructor(
editor: ICodeEditor,
@IInstantiationService instantiationService: IInstantiationService,
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
@IClipboardService private readonly _clipboardService: IClipboardService,
@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,
@IQuickInputService private readonly _quickInputService: IQuickInputService,
@IProgressService private readonly _progressService: IProgressService,
) {
super();
@ -86,6 +94,16 @@ export class CopyPasteController extends Disposable implements IEditorContributi
this._postPasteWidgetManager.tryShowSelector();
}
public pasteAs(preferredId?: string) {
this._editor.focus();
try {
this._pasteAsActionContext = { preferredId };
document.execCommand('paste');
} finally {
this._pasteAsActionContext = undefined;
}
}
public clearWidgets() {
this._postPasteWidgetManager.clear();
}
@ -208,11 +226,20 @@ export class CopyPasteController extends Disposable implements IEditorContributi
e.preventDefault();
e.stopImmediatePropagation();
if (this._pasteAsActionContext) {
this.showPasteAsPick(this._pasteAsActionContext.preferredId, allProviders, selections, dataTransfer, metadata);
} else {
this.doPasteInline(allProviders, selections, dataTransfer, metadata);
}
}
private doPasteInline(allProviders: readonly DocumentPasteEditProvider[], selections: readonly Selection[], dataTransfer: VSDataTransfer, metadata: CopyMetadata | undefined): void {
const p = createCancelablePromise(async (token) => {
const editor = this._editor;
if (!editor.hasModel()) {
return;
}
const model = editor.getModel();
const tokenSource = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection, undefined, token);
try {
@ -253,6 +280,71 @@ export class CopyPasteController extends Disposable implements IEditorContributi
this._currentPasteOperation = p;
}
private showPasteAsPick(preferredId: string | undefined, allProviders: readonly DocumentPasteEditProvider[], selections: readonly Selection[], dataTransfer: VSDataTransfer, metadata: CopyMetadata | undefined): void {
const p = createCancelablePromise(async (token) => {
const editor = this._editor;
if (!editor.hasModel()) {
return;
}
const model = editor.getModel();
const tokenSource = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection, undefined, token);
try {
await this.mergeInDataFromCopy(dataTransfer, metadata, tokenSource.token);
if (tokenSource.token.isCancellationRequested) {
return;
}
// Filter out any providers the don't match the full data transfer we will send them.
const supportedProviders = allProviders.filter(provider => isSupportedProvider(provider, dataTransfer));
const providerEdits = await this.getPasteEdits(supportedProviders, dataTransfer, model, selections, tokenSource.token);
if (tokenSource.token.isCancellationRequested) {
return;
}
if (!providerEdits.length) {
return;
}
let pickedEdit: DocumentPasteEdit | undefined;
if (typeof preferredId === 'string') {
// We are looking for a specific edit
pickedEdit = providerEdits.find(edit => edit.id === preferredId);
} else {
const selected = await this._quickInputService.pick(
providerEdits.map((edit): IQuickPickItem & { edit: DocumentPasteEdit } => ({
label: edit.label,
description: edit.id,
detail: edit.detail,
edit,
})), {
placeHolder: localize('pasteAsPickerPlaceholder', "Select Paste Action"),
});
pickedEdit = selected?.edit;
}
if (!pickedEdit) {
return;
}
const combinedWorkspaceEdit = createCombinedWorkspaceEdit(model.uri, selections, pickedEdit);
await this._bulkEditService.apply(combinedWorkspaceEdit, { editor: this._editor });
} finally {
tokenSource.dispose();
if (this._currentPasteOperation === p) {
this._currentPasteOperation = undefined;
}
}
});
this._progressService.withProgress({
location: ProgressLocation.Window,
title: localize('pasteAsProgress', "Running paste handlers"),
}, () => p);
}
private setCopyMetadata(dataTransfer: DataTransfer, metadata: CopyMetadata) {
dataTransfer.setData(vscodeClipboardMime, JSON.stringify(metadata));
}
@ -293,7 +385,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
}
}
private async getPasteEdits(providers: readonly DocumentPasteEditProvider[], dataTransfer: VSDataTransfer, model: ITextModel, selections: 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(
Promise.all(
providers.map(provider => provider.provideDocumentPasteEdits(model, selections, dataTransfer, token))

View File

@ -19,6 +19,8 @@ import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeat
import { localize } from 'vs/nls';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
const builtInLabel = localize('builtIn', 'Built-in');
abstract class SimplePasteAndDropProvider implements DocumentOnDropEditProvider, DocumentPasteEditProvider {
abstract readonly id: string;
@ -27,12 +29,12 @@ abstract class SimplePasteAndDropProvider implements DocumentOnDropEditProvider,
async provideDocumentPasteEdits(_model: ITextModel, _ranges: readonly IRange[], dataTransfer: VSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined> {
const edit = await this.getEdit(dataTransfer, token);
return edit ? { insertText: edit.insertText, label: edit.label } : undefined;
return edit ? { id: this.id, insertText: edit.insertText, label: edit.label, detail: edit.detail } : undefined;
}
async provideDocumentOnDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<DocumentOnDropEdit | undefined> {
const edit = await this.getEdit(dataTransfer, token);
return edit ? { insertText: edit.insertText, label: edit.label } : undefined;
return edit ? { id: this.id, insertText: edit.insertText, label: edit.label } : undefined;
}
protected abstract getEdit(dataTransfer: VSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined>;
@ -58,7 +60,9 @@ class DefaultTextProvider extends SimplePasteAndDropProvider {
const insertText = await textEntry.asString();
return {
id: this.id,
label: localize('text.label', "Insert Plain Text"),
detail: builtInLabel,
insertText
};
}
@ -101,7 +105,12 @@ class PathProvider extends SimplePasteAndDropProvider {
: localize('defaultDropProvider.uriList.path', "Insert Path");
}
return { insertText, label };
return {
id: this.id,
insertText,
label,
detail: builtInLabel,
};
}
}
@ -133,10 +142,12 @@ class RelativePathProvider extends SimplePasteAndDropProvider {
}
return {
id: this.id,
insertText: relativeUris.join(' '),
label: entries.length > 1
? localize('defaultDropProvider.uriList.relativePaths', "Insert Relative Paths")
: localize('defaultDropProvider.uriList.relativePath', "Insert Relative Path")
: localize('defaultDropProvider.uriList.relativePath', "Insert Relative Path"),
detail: builtInLabel,
};
}
}

View File

@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import { ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService';
import { WorkspaceEdit } from 'vs/editor/common/languages';
import { Range } from 'vs/editor/common/core/range';
export interface DropOrPasteEdit {
readonly label: string;
readonly insertText: string | { readonly snippet: string };
readonly additionalEdit?: WorkspaceEdit;
}
export function createCombinedWorkspaceEdit(uri: URI, ranges: readonly Range[], edit: DropOrPasteEdit): WorkspaceEdit {
return {
edits: [
...ranges.map(range =>
new ResourceTextEdit(uri,
typeof edit.insertText === 'string'
? { range, text: edit.insertText, insertAsSnippet: false }
: { range, text: edit.insertText.snippet, insertAsSnippet: true }
)),
...(edit.additionalEdit?.edits ?? [])
]
};
}

View File

@ -32,7 +32,7 @@ import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'
import * as search from 'vs/workbench/contrib/search/common/search';
import * as typeh from 'vs/workbench/contrib/typeHierarchy/common/typeHierarchy';
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IPasteEditProviderMetadataDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape } from '../common/extHost.protocol';
import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentDropEditProviderMetadata, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IPasteEditProviderMetadataDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape } from '../common/extHost.protocol';
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
export class MainThreadLanguageFeatures extends Disposable implements MainThreadLanguageFeaturesShape {
@ -907,8 +907,8 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread
private readonly _documentOnDropEditProviders = new Map<number, MainThreadDocumentOnDropEditProvider>();
$registerDocumentOnDropEditProvider(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, metadata: { id: string; dropMimeTypes: string[] }): void {
const provider = new MainThreadDocumentOnDropEditProvider(handle, extensionId, metadata, this._proxy, this._uriIdentService);
$registerDocumentOnDropEditProvider(handle: number, selector: IDocumentFilterDto[], metadata: IDocumentDropEditProviderMetadata): void {
const provider = new MainThreadDocumentOnDropEditProvider(handle, metadata, this._proxy, this._uriIdentService);
this._documentOnDropEditProviders.set(handle, provider);
this._registrations.set(handle, combinedDisposable(
this._languageFeaturesService.documentOnDropEditProvider.register(selector, provider),
@ -974,7 +974,9 @@ class MainThreadPasteEditProvider implements languages.DocumentPasteEditProvider
}
return {
id: result.id,
label: result.label,
detail: result.detail,
insertText: result.insertText,
additionalEdit: result.additionalEdit ? reviveWorkspaceEditDto(result.additionalEdit, this._uriIdentService, dataId => this.resolveFileData(request.id, dataId)) : undefined,
};
@ -992,17 +994,14 @@ class MainThreadDocumentOnDropEditProvider implements languages.DocumentOnDropEd
private readonly dataTransfers = new DataTransferCache();
readonly id: string;
readonly dropMimeTypes?: readonly string[];
constructor(
private readonly handle: number,
extensionId: ExtensionIdentifier,
metadata: { id: string; dropMimeTypes: readonly string[] } | undefined,
metadata: IDocumentDropEditProviderMetadata | undefined,
private readonly _proxy: ExtHostLanguageFeaturesShape,
@IUriIdentityService private readonly _uriIdentService: IUriIdentityService
) {
this.id = extensionId.value + (metadata ? '.' + metadata.id : '');
this.dropMimeTypes = metadata?.dropMimeTypes ?? ['*/*'];
}
@ -1015,6 +1014,7 @@ class MainThreadDocumentOnDropEditProvider implements languages.DocumentOnDropEd
return undefined;
}
return {
id: edit.id,
label: edit.label,
insertText: edit.insertText,
additionalEdit: reviveWorkspaceEditDto(edit.additionalEdit, this._uriIdentService, dataId => this.resolveDocumentOnDropFileData(request.id, dataId)),

View File

@ -413,7 +413,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
$registerSelectionRangeProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerTypeHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void;
$registerDocumentOnDropEditProvider(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, metadata?: { id: string; dropMimeTypes: readonly string[] }): void;
$registerDocumentOnDropEditProvider(handle: number, selector: IDocumentFilterDto[], metadata?: IDocumentDropEditProviderMetadata): void;
$resolvePasteFileData(handle: number, requestId: number, dataId: string): Promise<VSBuffer>;
$resolveDocumentOnDropFileData(handle: number, requestId: number, dataId: string): Promise<VSBuffer>;
$setLanguageConfiguration(handle: number, languageId: string, configuration: ILanguageConfigurationDto): void;
@ -1835,12 +1835,19 @@ export interface IPasteEditProviderMetadataDto {
}
export interface IPasteEditDto {
id: string;
label: string;
detail: string;
insertText: string | { snippet: string };
additionalEdit?: IWorkspaceEditDto;
}
export interface IDocumentDropEditProviderMetadata {
dropMimeTypes: readonly string[];
}
export interface IDocumentOnDropEditDto {
id: string;
label: string;
insertText: string | { snippet: string };
additionalEdit?: IWorkspaceEditDto;

View File

@ -538,7 +538,9 @@ class DocumentPasteEditProvider {
}
return {
id: edit.id ? 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),
detail: this._extension.displayName || this._extension.name,
insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined) : undefined,
};
@ -1750,6 +1752,7 @@ class DocumentOnDropEditAdapter {
return undefined;
}
return {
id: edit.id ? 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),
insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined) : undefined,
@ -2393,7 +2396,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
const handle = this._nextHandle();
this._adapter.set(handle, new AdapterData(new DocumentOnDropEditAdapter(this._proxy, this._documents, provider, handle, extension), extension));
this._proxy.$registerDocumentOnDropEditProvider(handle, this._transformDocumentSelector(selector, extension), extension.identifier, isProposedApiEnabled(extension, 'dropMetadata') ? metadata : undefined);
this._proxy.$registerDocumentOnDropEditProvider(handle, this._transformDocumentSelector(selector, extension), isProposedApiEnabled(extension, 'dropMetadata') ? metadata : undefined);
return this._createDisposable(handle);
}

View File

@ -2675,6 +2675,8 @@ export class DataTransfer implements vscode.DataTransfer {
@es5ClassCompat
export class DocumentDropEdit {
id: string | undefined;
insertText: string | SnippetString;
additionalEdit?: WorkspaceEdit;
@ -2686,13 +2688,16 @@ export class DocumentDropEdit {
@es5ClassCompat
export class DocumentPasteEdit {
id: string;
label: string;
insertText: string | SnippetString;
additionalEdit?: WorkspaceEdit;
constructor(insertText: string | SnippetString, label: string) {
constructor(insertText: string | SnippetString, id: string, label: string) {
this.id = id;
this.label = label;
this.insertText = insertText;
}

View File

@ -44,6 +44,13 @@ declare module 'vscode' {
* An operation applied on paste
*/
class DocumentPasteEdit {
/**
* Identifies the type of edit.
*
* This id should be unique within the extension but does not need to be unique across extensions.
*/
id: string;
/**
* Human readable label that describes the edit.
*/
@ -64,7 +71,7 @@ declare module 'vscode' {
*
* TODO: Reverse args, but this will break existing consumers :(
*/
constructor(insertText: string | SnippetString, label: string);
constructor(insertText: string | SnippetString, id: string, label: string);
}
interface DocumentPasteProviderMetadata {

View File

@ -8,6 +8,13 @@ declare module 'vscode' {
// https://github.com/microsoft/vscode/issues/179430
export interface DocumentDropEdit {
/**
* Identifies the type of edit.
*
* This id should be unique within the extension but does not need to be unique across extensions.
*/
id: string;
/**
* Human readable label that describes the edit.
*/
@ -15,13 +22,6 @@ declare module 'vscode' {
}
export interface DocumentDropEditProviderMetadata {
/**
* Unique identifier for the provider.
*
* This id should be unique within the extension but does not need to be unique across extensions.
*/
readonly id: string;
/**
* List of data transfer types that the provider supports.
*