mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
Iterate on paste edit provider api (#151477)
* Iterate on paste edit provider api For #30066 - Pass all selections to paste providers. For #151326 - Introduce `DocumentPasteEdit` as return type. This new type uses an `insertText` that is applied to every paste location (for multicursor), plus an optional additional edit - Add `DocumentPasteProviderMetadata`. This lets extensions tell us which types of mimetypes they are interested in, letting us avoid round trips if no extensions care about the pasted data * Correctly batch insertText
This commit is contained in:
parent
5a32c3ff17
commit
370dfd5fee
|
@ -4,23 +4,29 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { tryInsertUriList } from './dropIntoEditor';
|
||||
import { tryGetUriListSnippet } from './dropIntoEditor';
|
||||
|
||||
export function registerPasteProvider(selector: vscode.DocumentSelector) {
|
||||
return vscode.languages.registerDocumentPasteEditProvider(selector, new class implements vscode.DocumentPasteEditProvider {
|
||||
|
||||
async provideDocumentPasteEdits(
|
||||
document: vscode.TextDocument,
|
||||
range: vscode.Range,
|
||||
_ranges: readonly vscode.Range[],
|
||||
dataTransfer: vscode.DataTransfer,
|
||||
token: vscode.CancellationToken,
|
||||
): Promise<vscode.SnippetTextEdit | undefined> {
|
||||
): Promise<vscode.DocumentPasteEdit | undefined> {
|
||||
const enabled = vscode.workspace.getConfiguration('markdown', document).get('experimental.editor.pasteLinks.enabled', false);
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
return tryInsertUriList(document, range, dataTransfer, token);
|
||||
const snippet = await tryGetUriListSnippet(document, dataTransfer, token);
|
||||
if (snippet) {
|
||||
return { insertText: snippet };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}, {
|
||||
pasteMimeTypes: ['text/uri-list']
|
||||
});
|
||||
}
|
||||
|
|
|
@ -28,16 +28,20 @@ export function registerDropIntoEditor(selector: vscode.DocumentSelector) {
|
|||
async provideDocumentOnDropEdits(document: vscode.TextDocument, position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.SnippetTextEdit | undefined> {
|
||||
const enabled = vscode.workspace.getConfiguration('markdown', document).get('editor.drop.enabled', true);
|
||||
if (!enabled) {
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const replacementRange = new vscode.Range(position, position);
|
||||
return tryInsertUriList(document, replacementRange, dataTransfer, token);
|
||||
const snippet = await tryGetUriListSnippet(document, dataTransfer, token);
|
||||
if (snippet) {
|
||||
return new vscode.SnippetTextEdit(replacementRange, snippet);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function tryInsertUriList(document: vscode.TextDocument, replacementRange: vscode.Range, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.SnippetTextEdit | undefined> {
|
||||
export async function tryGetUriListSnippet(document: vscode.TextDocument, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.SnippetString | undefined> {
|
||||
const urlList = await dataTransfer.get('text/uri-list')?.asString();
|
||||
if (!urlList || token.isCancellationRequested) {
|
||||
return undefined;
|
||||
|
@ -72,5 +76,5 @@ export async function tryInsertUriList(document: vscode.TextDocument, replacemen
|
|||
}
|
||||
});
|
||||
|
||||
return new vscode.SnippetTextEdit(replacementRange, snippet);
|
||||
return snippet;
|
||||
}
|
||||
|
|
|
@ -724,10 +724,21 @@ export interface CodeActionProvider {
|
|||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface DocumentPasteEditProvider {
|
||||
prepareDocumentPaste?(model: model.ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<undefined | VSDataTransfer>;
|
||||
export interface DocumentPasteEdit {
|
||||
insertSnippet: string;
|
||||
additionalEdit?: WorkspaceEdit;
|
||||
}
|
||||
|
||||
provideDocumentPasteEdits(model: model.ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<WorkspaceEdit | SnippetTextEdit | undefined>;
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface DocumentPasteEditProvider {
|
||||
|
||||
readonly pasteMimeTypes: readonly string[];
|
||||
|
||||
prepareDocumentPaste?(model: model.ITextModel, selections: readonly Selection[], dataTransfer: VSDataTransfer, token: CancellationToken): Promise<undefined | VSDataTransfer>;
|
||||
|
||||
provideDocumentPasteEdits(model: model.ITextModel, selections: readonly Selection[], dataTransfer: VSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DataTransfers } from 'vs/base/browser/dnd';
|
||||
import { addDisposableListener } from 'vs/base/browser/dom';
|
||||
import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
@ -15,7 +16,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||
import { IBulkEditService, ResourceEdit } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { DocumentPasteEditProvider, SnippetTextEdit, WorkspaceEdit } from 'vs/editor/common/languages';
|
||||
import { DocumentPasteEdit, DocumentPasteEditProvider } from 'vs/editor/common/languages';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||
import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';
|
||||
|
@ -26,15 +27,14 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
|
|||
const vscodeClipboardMime = 'application/vnd.code.copyId';
|
||||
|
||||
const defaultPasteEditProvider = new class implements DocumentPasteEditProvider {
|
||||
async provideDocumentPasteEdits(model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<WorkspaceEdit | undefined> {
|
||||
pasteMimeTypes = [Mimes.text, 'text'];
|
||||
|
||||
async provideDocumentPasteEdits(model: ITextModel, selections: Selection[], dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<DocumentPasteEdit | undefined> {
|
||||
const textDataTransfer = dataTransfer.get(Mimes.text) ?? dataTransfer.get('text');
|
||||
if (textDataTransfer) {
|
||||
const text = await textDataTransfer.asString();
|
||||
return {
|
||||
edits: [{
|
||||
resource: model.uri,
|
||||
edit: { range: selection, text },
|
||||
}]
|
||||
insertSnippet: text
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -76,8 +76,8 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
}
|
||||
|
||||
const model = editor.getModel();
|
||||
const selection = this._editor.getSelection();
|
||||
if (!model || !selection) {
|
||||
const selections = this._editor.getSelections();
|
||||
if (!model || !selections?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
|
||||
const promise = createCancelablePromise(async token => {
|
||||
const results = await Promise.all(providers.map(provider => {
|
||||
return provider.prepareDocumentPaste!(model, selection, dataTransfer, token);
|
||||
return provider.prepareDocumentPaste!(model, selections, dataTransfer, token);
|
||||
}));
|
||||
|
||||
for (const result of results) {
|
||||
|
@ -115,8 +115,8 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
}));
|
||||
|
||||
this._register(addDisposableListener(container, 'paste', async (e: ClipboardEvent) => {
|
||||
const selection = this._editor.getSelection();
|
||||
if (!e.clipboardData || !selection || !editor.hasModel()) {
|
||||
const selections = this._editor.getSelections();
|
||||
if (!e.clipboardData || !selections?.length || !editor.hasModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -125,21 +125,20 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
return;
|
||||
}
|
||||
|
||||
const originalDocVersion = model.getVersionId();
|
||||
const handle = e.clipboardData?.getData(vscodeClipboardMime);
|
||||
if (typeof handle !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
const providers = this._languageFeaturesService.documentPasteEditProvider.ordered(model);
|
||||
if (!providers.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const handle = e.clipboardData?.getData(vscodeClipboardMime);
|
||||
if (typeof handle !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
|
||||
const originalDocVersion = model.getVersionId();
|
||||
const tokenSource = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection);
|
||||
|
||||
try {
|
||||
|
@ -163,16 +162,25 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
dataTransfer.delete(vscodeClipboardMime);
|
||||
|
||||
for (const provider of [...providers, defaultPasteEditProvider]) {
|
||||
const edit = await provider.provideDocumentPasteEdits(model, selection, dataTransfer, tokenSource.token);
|
||||
if (!provider.pasteMimeTypes.some(type => {
|
||||
if (type.toLowerCase() === DataTransfers.FILES.toLowerCase()) {
|
||||
return [...dataTransfer.values()].some(item => item.asFile());
|
||||
}
|
||||
return dataTransfer.has(type);
|
||||
})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const edit = await provider.provideDocumentPasteEdits(model, selections, dataTransfer, tokenSource.token);
|
||||
if (originalDocVersion !== model.getVersionId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (edit) {
|
||||
if ((edit as WorkspaceEdit).edits) {
|
||||
await this._bulkEditService.apply(ResourceEdit.convert(edit as WorkspaceEdit), { editor });
|
||||
} else {
|
||||
performSnippetEdit(editor, edit as SnippetTextEdit);
|
||||
performSnippetEdit(editor, edit.insertSnippet, selections);
|
||||
|
||||
if (edit.additionalEdit) {
|
||||
await this._bulkEditService.apply(ResourceEdit.convert(edit.additionalEdit), { editor });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||
import { EditorCommand, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { ISelection } from 'vs/editor/common/core/selection';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { CompletionItem, CompletionItemKind, CompletionItemProvider, SnippetTextEdit } from 'vs/editor/common/languages';
|
||||
|
@ -335,13 +336,20 @@ registerEditorCommand(new CommandCtor({
|
|||
|
||||
// ---
|
||||
|
||||
export function performSnippetEdit(editor: ICodeEditor, edit: SnippetTextEdit) {
|
||||
export function performSnippetEdit(editor: ICodeEditor, snippet: string, selections: ISelection[]): boolean;
|
||||
export function performSnippetEdit(editor: ICodeEditor, edit: SnippetTextEdit): boolean;
|
||||
export function performSnippetEdit(editor: ICodeEditor, editOrSnippet: string | SnippetTextEdit, selections?: ISelection[]): boolean {
|
||||
const controller = SnippetController2.get(editor);
|
||||
if (!controller) {
|
||||
return false;
|
||||
}
|
||||
editor.focus();
|
||||
editor.setSelection(edit.range);
|
||||
controller.insert(edit.snippet);
|
||||
if (typeof editOrSnippet === 'string') {
|
||||
editor.setSelections(selections ?? []);
|
||||
controller.insert(editOrSnippet);
|
||||
} else {
|
||||
editor.setSelection(editOrSnippet.range);
|
||||
controller.insert(editOrSnippet.snippet);
|
||||
}
|
||||
return controller.isInSnippet();
|
||||
}
|
||||
|
|
|
@ -30,7 +30,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, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceEditDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape, reviveWorkspaceEditDto } from '../common/extHost.protocol';
|
||||
import { ExtHostContext, ExtHostLanguageFeaturesShape, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape, reviveWorkspaceEditDto } from '../common/extHost.protocol';
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)
|
||||
export class MainThreadLanguageFeatures extends Disposable implements MainThreadLanguageFeaturesShape {
|
||||
|
@ -368,21 +368,22 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread
|
|||
|
||||
// --- copy paste action provider
|
||||
|
||||
$registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean): void {
|
||||
$registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean, pasteMimeTypes: readonly string[]): void {
|
||||
const provider: languages.DocumentPasteEditProvider = {
|
||||
pasteMimeTypes: pasteMimeTypes,
|
||||
|
||||
prepareDocumentPaste: supportsCopy
|
||||
? async (model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<VSDataTransfer | undefined> => {
|
||||
? async (model: ITextModel, selections: Selection[], dataTransfer: VSDataTransfer, token: CancellationToken): Promise<VSDataTransfer | undefined> => {
|
||||
const dataTransferDto = await typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
|
||||
if (token.isCancellationRequested) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = await this._proxy.$prepareDocumentPaste(handle, model.uri, selection, dataTransferDto, token);
|
||||
const result = await this._proxy.$prepareDocumentPaste(handle, model.uri, selections, dataTransferDto, token);
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
const dataTransferOut = new VSDataTransfer();
|
||||
result.items.forEach(([type, item]) => {
|
||||
dataTransferOut.replace(type, createStringDataTransferItem(item.asString));
|
||||
|
@ -391,16 +392,17 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread
|
|||
}
|
||||
: undefined,
|
||||
|
||||
provideDocumentPasteEdits: async (model: ITextModel, selection: Selection, dataTransfer: VSDataTransfer, token: CancellationToken) => {
|
||||
provideDocumentPasteEdits: async (model: ITextModel, selections: Selection[], dataTransfer: VSDataTransfer, token: CancellationToken) => {
|
||||
const d = await typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
|
||||
const result = await this._proxy.$providePasteEdits(handle, model.uri, selection, d, token);
|
||||
const result = await this._proxy.$providePasteEdits(handle, model.uri, selections, d, token);
|
||||
if (!result) {
|
||||
return;
|
||||
} else if ((result as IWorkspaceEditDto).edits) {
|
||||
return reviveWorkspaceEditDto(result as IWorkspaceEditDto);
|
||||
} else {
|
||||
return result as languages.SnippetTextEdit;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
insertSnippet: result.insertSnippet,
|
||||
additionalEdit: result.additionalEdit ? reviveWorkspaceEditDto(result.additionalEdit) : undefined,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -457,9 +457,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
registerCodeActionsProvider(selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerCodeActionProvider(extension, checkSelector(selector), provider, metadata);
|
||||
},
|
||||
registerDocumentPasteEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider): vscode.Disposable {
|
||||
registerDocumentPasteEditProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider, metadata: vscode.DocumentPasteProviderMetadata): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension, 'documentPaste');
|
||||
return extHostLanguageFeatures.registerDocumentPasteEditProvider(extension, checkSelector(selector), provider);
|
||||
return extHostLanguageFeatures.registerDocumentPasteEditProvider(extension, checkSelector(selector), provider, metadata);
|
||||
},
|
||||
registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider);
|
||||
|
|
|
@ -372,7 +372,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
|||
$registerLinkedEditingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string, supportsResolve: boolean): void;
|
||||
$registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean): void;
|
||||
$registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], supportsCopy: boolean, pasteMimeTypes: readonly string[]): void;
|
||||
$registerDocumentFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void;
|
||||
$registerRangeFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void;
|
||||
$registerOnTypeFormattingSupport(handle: number, selector: IDocumentFilterDto[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void;
|
||||
|
@ -1713,6 +1713,11 @@ export interface IInlineValueContextDto {
|
|||
|
||||
export type ITypeHierarchyItemDto = Dto<TypeHierarchyItem>;
|
||||
|
||||
export interface IPasteEditDto {
|
||||
insertSnippet: string;
|
||||
additionalEdit?: IWorkspaceEditDto;
|
||||
}
|
||||
|
||||
export interface ExtHostLanguageFeaturesShape {
|
||||
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<languages.DocumentSymbol[] | undefined>;
|
||||
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<ICodeLensListDto | undefined>;
|
||||
|
@ -1731,8 +1736,8 @@ export interface ExtHostLanguageFeaturesShape {
|
|||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: languages.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined>;
|
||||
$resolveCodeAction(handle: number, id: ChainedCacheId, token: CancellationToken): Promise<IWorkspaceEditDto | undefined>;
|
||||
$releaseCodeActions(handle: number, cacheId: number): void;
|
||||
$prepareDocumentPaste(handle: number, uri: UriComponents, range: IRange, dataTransfer: DataTransferDTO, token: CancellationToken): Promise<DataTransferDTO | undefined>;
|
||||
$providePasteEdits(handle: number, uri: UriComponents, range: IRange, dataTransfer: DataTransferDTO, token: CancellationToken): Promise<IWorkspaceEditDto | Dto<languages.SnippetTextEdit> | undefined>;
|
||||
$prepareDocumentPaste(handle: number, uri: UriComponents, ranges: IRange[], dataTransfer: DataTransferDTO, token: CancellationToken): Promise<DataTransferDTO | undefined>;
|
||||
$providePasteEdits(handle: number, uri: UriComponents, ranges: IRange[], dataTransfer: DataTransferDTO, token: CancellationToken): Promise<IPasteEditDto | undefined>;
|
||||
$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: languages.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
|
||||
$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: languages.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
|
||||
$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: languages.FormattingOptions, token: CancellationToken): Promise<ISingleEditOperation[] | undefined>;
|
||||
|
|
|
@ -7,7 +7,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
|||
import { mixin } from 'vs/base/common/objects';
|
||||
import type * as vscode from 'vscode';
|
||||
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, Location, InlineCompletionTriggerKindNew, InlineCompletionTriggerKind, WorkspaceEdit } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { Range, Disposable, CompletionList, SnippetString, CodeActionKind, SymbolInformation, DocumentSymbol, SemanticTokensEdits, SemanticTokens, SemanticTokensEdit, Location, InlineCompletionTriggerKindNew, InlineCompletionTriggerKind } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ISingleEditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import * as languages from 'vs/editor/common/languages';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
|
@ -494,40 +494,39 @@ class DocumentPasteEditProvider {
|
|||
private readonly _handle: number,
|
||||
) { }
|
||||
|
||||
async prepareDocumentPaste(resource: URI, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
|
||||
async prepareDocumentPaste(resource: URI, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
|
||||
if (!this._provider.prepareDocumentPaste) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const vscodeRange = typeConvert.Range.to(range);
|
||||
const vscodeRanges = ranges.map(range => typeConvert.Range.to(range));
|
||||
|
||||
const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, () => {
|
||||
throw new NotImplementedError();
|
||||
});
|
||||
await this._provider.prepareDocumentPaste(doc, vscodeRange, dataTransfer, token);
|
||||
await this._provider.prepareDocumentPaste(doc, vscodeRanges, dataTransfer, token);
|
||||
|
||||
return typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
|
||||
}
|
||||
|
||||
async providePasteEdits(requestId: number, resource: URI, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<undefined | extHostProtocol.IWorkspaceEditDto | Dto<languages.SnippetTextEdit>> {
|
||||
async providePasteEdits(requestId: number, resource: URI, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<undefined | extHostProtocol.IPasteEditDto> {
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const vscodeRange = typeConvert.Range.to(range);
|
||||
const vscodeRanges = ranges.map(range => typeConvert.Range.to(range));
|
||||
|
||||
const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, async (index) => {
|
||||
return (await this._proxy.$resolveDocumentOnDropFileData(this._handle, requestId, index)).buffer;
|
||||
});
|
||||
|
||||
const edit = await this._provider.provideDocumentPasteEdits(doc, vscodeRange, dataTransfer, token);
|
||||
const edit = await this._provider.provideDocumentPasteEdits(doc, vscodeRanges, dataTransfer, token);
|
||||
if (!edit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (edit instanceof WorkspaceEdit) {
|
||||
return typeConvert.WorkspaceEdit.from(edit);
|
||||
} else {
|
||||
return typeConvert.SnippetTextEdit.from(edit as vscode.SnippetTextEdit);
|
||||
}
|
||||
return {
|
||||
insertSnippet: typeof edit.insertText === 'string' ? edit.insertText : edit.insertText.value,
|
||||
additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit) : undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2461,19 +2460,19 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
|
|||
|
||||
// --- copy/paste actions
|
||||
|
||||
registerDocumentPasteEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider): vscode.Disposable {
|
||||
registerDocumentPasteEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider, metadata: vscode.DocumentPasteProviderMetadata): vscode.Disposable {
|
||||
const handle = this._nextHandle();
|
||||
this._adapter.set(handle, new AdapterData(new DocumentPasteEditProvider(this._proxy, this._documents, provider, handle), extension));
|
||||
this._proxy.$registerPasteEditProvider(handle, this._transformDocumentSelector(selector), !!provider.prepareDocumentPaste);
|
||||
this._proxy.$registerPasteEditProvider(handle, this._transformDocumentSelector(selector), !!provider.prepareDocumentPaste, metadata.pasteMimeTypes);
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$prepareDocumentPaste(handle: number, resource: UriComponents, range: IRange, dataTransfer: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
|
||||
return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.prepareDocumentPaste(URI.revive(resource), range, dataTransfer, token), undefined, token);
|
||||
$prepareDocumentPaste(handle: number, resource: UriComponents, ranges: IRange[], dataTransfer: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
|
||||
return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.prepareDocumentPaste(URI.revive(resource), ranges, dataTransfer, token), undefined, token);
|
||||
}
|
||||
|
||||
$providePasteEdits(handle: number, resource: UriComponents, range: IRange, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IWorkspaceEditDto | Dto<languages.SnippetTextEdit> | undefined> {
|
||||
return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.providePasteEdits(0, URI.revive(resource), range, dataTransferDto, token), undefined, token);
|
||||
$providePasteEdits(handle: number, resource: UriComponents, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IPasteEditDto | undefined> {
|
||||
return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.providePasteEdits(0, URI.revive(resource), ranges, dataTransferDto, token), undefined, token);
|
||||
}
|
||||
|
||||
// --- configuration
|
||||
|
|
|
@ -19,11 +19,11 @@ declare module 'vscode' {
|
|||
* a {@link DataTransfer} and is passed back to the provider in {@link provideDocumentPasteEdits}.
|
||||
*
|
||||
* @param document Document where the copy took place.
|
||||
* @param range Range being copied in the `document`.
|
||||
* @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 token A cancellation token.
|
||||
*/
|
||||
prepareDocumentPaste?(document: TextDocument, range: Range, dataTransfer: DataTransfer, token: CancellationToken): void | Thenable<void>;
|
||||
prepareDocumentPaste?(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): void | Thenable<void>;
|
||||
|
||||
/**
|
||||
* Invoked before the user pastes into a document.
|
||||
|
@ -31,16 +31,40 @@ declare module 'vscode' {
|
|||
* In this method, extensions can return a workspace edit that replaces the standard pasting behavior.
|
||||
*
|
||||
* @param document Document being pasted into
|
||||
* @param range Currently selected range in the document.
|
||||
* @param ranges Currently selected ranges in the document.
|
||||
* @param dataTransfer The data transfer associated with the paste.
|
||||
* @param token A cancellation token.
|
||||
*
|
||||
* @return Optional workspace edit that applies the paste. Return undefined to use standard pasting.
|
||||
*/
|
||||
provideDocumentPasteEdits(document: TextDocument, range: Range, dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<WorkspaceEdit | SnippetTextEdit>;
|
||||
provideDocumentPasteEdits(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<DocumentPasteEdit>;
|
||||
}
|
||||
|
||||
/**
|
||||
* An operation applied on paste
|
||||
*/
|
||||
interface DocumentPasteEdit {
|
||||
/**
|
||||
* The text or snippet to insert at the pasted locations.
|
||||
*/
|
||||
readonly insertText: string | SnippetString;
|
||||
|
||||
/**
|
||||
* An optional additional edit to apply on paste.
|
||||
*/
|
||||
readonly additionalEdit?: WorkspaceEdit;
|
||||
}
|
||||
|
||||
interface DocumentPasteProviderMetadata {
|
||||
/**
|
||||
* Mime types that `provideDocumentPasteEdits` should be invoked for.
|
||||
*
|
||||
* Use the special `files` mimetype to indicate the provider should be invoked if any files are present in the `DataTransfer`.
|
||||
*/
|
||||
readonly pasteMimeTypes: readonly string[];
|
||||
}
|
||||
|
||||
namespace languages {
|
||||
export function registerDocumentPasteEditProvider(selector: DocumentSelector, provider: DocumentPasteEditProvider): Disposable;
|
||||
export function registerDocumentPasteEditProvider(selector: DocumentSelector, provider: DocumentPasteEditProvider, metadata: DocumentPasteProviderMetadata): Disposable;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue