mirror of
https://github.com/Microsoft/vscode
synced 2024-08-28 05:19:39 +00:00
Update text editor drop proposal (#151552)
This updates the text editor drop proposal (#142990). This change introduces `DocumentDropEdit` which removes the need for `SnippetTextEdit`. This interface may also be extended in the future with additional metadata
This commit is contained in:
parent
83b94a5c03
commit
d7c90c2b2b
|
@ -25,16 +25,15 @@ const imageFileExtensions = new Set<string>([
|
|||
|
||||
export function registerDropIntoEditor(selector: vscode.DocumentSelector) {
|
||||
return vscode.languages.registerDocumentOnDropEditProvider(selector, new class implements vscode.DocumentOnDropEditProvider {
|
||||
async provideDocumentOnDropEdits(document: vscode.TextDocument, position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.SnippetTextEdit | undefined> {
|
||||
async provideDocumentOnDropEdits(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);
|
||||
if (!enabled) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const replacementRange = new vscode.Range(position, position);
|
||||
const snippet = await tryGetUriListSnippet(document, dataTransfer, token);
|
||||
if (snippet) {
|
||||
return new vscode.SnippetTextEdit(replacementRange, snippet);
|
||||
return { insertText: snippet };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
@ -725,7 +725,7 @@ export interface CodeActionProvider {
|
|||
* @internal
|
||||
*/
|
||||
export interface DocumentPasteEdit {
|
||||
insertSnippet: string;
|
||||
insertText: string | { snippet: string };
|
||||
additionalEdit?: WorkspaceEdit;
|
||||
}
|
||||
|
||||
|
@ -1134,11 +1134,6 @@ export interface DocumentSymbolProvider {
|
|||
|
||||
export type TextEdit = { range: IRange; text: string; eol?: model.EndOfLineSequence };
|
||||
|
||||
export interface SnippetTextEdit {
|
||||
range: IRange;
|
||||
snippet: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to format a model
|
||||
*/
|
||||
|
@ -1811,10 +1806,17 @@ export enum ExternalUriOpenerPriority {
|
|||
Preferred = 3,
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface DocumentOnDropEdit {
|
||||
insertText: string | { snippet: string };
|
||||
additionalEdit?: WorkspaceEdit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface DocumentOnDropEditProvider {
|
||||
provideDocumentOnDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): ProviderResult<SnippetTextEdit>;
|
||||
provideDocumentOnDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): ProviderResult<DocumentOnDropEdit>;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ 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';
|
||||
import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2';
|
||||
import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
|
@ -34,7 +35,7 @@ const defaultPasteEditProvider = new class implements DocumentPasteEditProvider
|
|||
if (textDataTransfer) {
|
||||
const text = await textDataTransfer.asString();
|
||||
return {
|
||||
insertSnippet: text
|
||||
insertText: text
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -177,7 +178,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
|
|||
}
|
||||
|
||||
if (edit) {
|
||||
performSnippetEdit(editor, edit.insertSnippet, selections);
|
||||
performSnippetEdit(editor, typeof edit.insertText === 'string' ? SnippetParser.escape(edit.insertText) : edit.insertText.snippet, selections);
|
||||
|
||||
if (edit.additionalEdit) {
|
||||
await this._bulkEditService.apply(ResourceEdit.convert(edit.additionalEdit), { editor });
|
||||
|
|
|
@ -13,14 +13,17 @@ import { URI } from 'vs/base/common/uri';
|
|||
import { toVSDataTransfer } from 'vs/editor/browser/dnd';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
|
||||
import { IBulkEditService, ResourceEdit } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Selection, SelectionDirection } from 'vs/editor/common/core/selection';
|
||||
import { IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { DocumentOnDropEditProvider, SnippetTextEdit } from 'vs/editor/common/languages';
|
||||
import { DocumentOnDropEdit, DocumentOnDropEditProvider } 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';
|
||||
import { performSnippetEdit } from 'vs/editor/contrib/snippet/browser/snippetController2';
|
||||
import { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { extractEditorsDropData } from 'vs/platform/dnd/browser/dnd';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
@ -37,6 +40,7 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
|
|||
@IInstantiationService private readonly _instantiationService: IInstantiationService,
|
||||
@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IBulkEditService private readonly _bulkEditService: IBulkEditService,
|
||||
) {
|
||||
super();
|
||||
|
||||
|
@ -87,7 +91,12 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
|
|||
}
|
||||
|
||||
if (edit) {
|
||||
performSnippetEdit(editor, edit);
|
||||
const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);
|
||||
performSnippetEdit(editor, typeof edit.insertText === 'string' ? SnippetParser.escape(edit.insertText) : edit.insertText.snippet, [Selection.fromRange(range, SelectionDirection.LTR)]);
|
||||
|
||||
if (edit.additionalEdit) {
|
||||
await this._bulkEditService.apply(ResourceEdit.convert(edit.additionalEdit), { editor });
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -121,24 +130,26 @@ class DefaultOnDropProvider implements DocumentOnDropEditProvider {
|
|||
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
|
||||
) { }
|
||||
|
||||
async provideDocumentOnDropEdits(model: ITextModel, position: IPosition, dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<SnippetTextEdit | undefined> {
|
||||
const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column);
|
||||
|
||||
async provideDocumentOnDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<DocumentOnDropEdit | undefined> {
|
||||
const urlListEntry = dataTransfer.get('text/uri-list');
|
||||
if (urlListEntry) {
|
||||
const urlList = await urlListEntry.asString();
|
||||
return this.doUriListDrop(range, urlList);
|
||||
const snippet = this.getUriListInsertText(urlList);
|
||||
if (snippet) {
|
||||
return { insertText: snippet };
|
||||
}
|
||||
}
|
||||
|
||||
const textEntry = dataTransfer.get('text') ?? dataTransfer.get(Mimes.text);
|
||||
if (textEntry) {
|
||||
const text = await textEntry.asString();
|
||||
return { range, snippet: text };
|
||||
return { insertText: text };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private doUriListDrop(range: Range, urlList: string): SnippetTextEdit | undefined {
|
||||
private getUriListInsertText(urlList: string): string | undefined {
|
||||
const uris: URI[] = [];
|
||||
for (const resource of urlList.split('\n')) {
|
||||
try {
|
||||
|
@ -152,7 +163,7 @@ class DefaultOnDropProvider implements DocumentOnDropEditProvider {
|
|||
return;
|
||||
}
|
||||
|
||||
const snippet = uris
|
||||
return uris
|
||||
.map(uri => {
|
||||
const root = this._workspaceContextService.getWorkspaceFolder(uri);
|
||||
if (root) {
|
||||
|
@ -164,8 +175,6 @@ class DefaultOnDropProvider implements DocumentOnDropEditProvider {
|
|||
return uri.fsPath;
|
||||
})
|
||||
.join(' ');
|
||||
|
||||
return { range, snippet };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ 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';
|
||||
import { CompletionItem, CompletionItemKind, CompletionItemProvider } from 'vs/editor/common/languages';
|
||||
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||
|
@ -336,20 +336,13 @@ registerEditorCommand(new CommandCtor({
|
|||
|
||||
// ---
|
||||
|
||||
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 {
|
||||
export function performSnippetEdit(editor: ICodeEditor, snippet: string, selections: ISelection[]): boolean {
|
||||
const controller = SnippetController2.get(editor);
|
||||
if (!controller) {
|
||||
return false;
|
||||
}
|
||||
editor.focus();
|
||||
if (typeof editOrSnippet === 'string') {
|
||||
editor.setSelections(selections ?? []);
|
||||
controller.insert(editOrSnippet);
|
||||
} else {
|
||||
editor.setSelection(editOrSnippet.range);
|
||||
controller.insert(editOrSnippet.snippet);
|
||||
}
|
||||
editor.setSelections(selections ?? []);
|
||||
controller.insert(snippet);
|
||||
return controller.isInSnippet();
|
||||
}
|
||||
|
|
5
src/vs/monaco.d.ts
vendored
5
src/vs/monaco.d.ts
vendored
|
@ -6758,11 +6758,6 @@ declare namespace monaco.languages {
|
|||
eol?: editor.EndOfLineSequence;
|
||||
};
|
||||
|
||||
export interface SnippetTextEdit {
|
||||
range: IRange;
|
||||
snippet: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to format a model
|
||||
*/
|
||||
|
|
|
@ -400,7 +400,7 @@ export class MainThreadLanguageFeatures extends Disposable implements MainThread
|
|||
}
|
||||
|
||||
return {
|
||||
insertSnippet: result.insertSnippet,
|
||||
insertText: result.insertText,
|
||||
additionalEdit: result.additionalEdit ? reviveWorkspaceEditDto(result.additionalEdit) : undefined,
|
||||
};
|
||||
}
|
||||
|
@ -935,11 +935,18 @@ class MainThreadDocumentOnDropEditProvider implements languages.DocumentOnDropEd
|
|||
private readonly _proxy: ExtHostLanguageFeaturesShape,
|
||||
) { }
|
||||
|
||||
async provideDocumentOnDropEdits(model: ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<languages.SnippetTextEdit | null | undefined> {
|
||||
async provideDocumentOnDropEdits(model: ITextModel, position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<languages.DocumentOnDropEdit | null | undefined> {
|
||||
const request = this.dataTransfers.add(dataTransfer);
|
||||
try {
|
||||
const dataTransferDto = await typeConvert.DataTransfer.toDataTransferDTO(dataTransfer);
|
||||
return await this._proxy.$provideDocumentOnDropEdits(this.handle, request.id, model.uri, position, dataTransferDto, token);
|
||||
const edit = await this._proxy.$provideDocumentOnDropEdits(this.handle, request.id, model.uri, position, dataTransferDto, token);
|
||||
if (!edit) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
insertText: edit.insertText,
|
||||
additionalEdit: reviveWorkspaceEditDto(edit.additionalEdit),
|
||||
};
|
||||
} finally {
|
||||
request.dispose();
|
||||
}
|
||||
|
|
|
@ -1267,7 +1267,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
SignatureHelpTriggerKind: extHostTypes.SignatureHelpTriggerKind,
|
||||
SignatureInformation: extHostTypes.SignatureInformation,
|
||||
SnippetString: extHostTypes.SnippetString,
|
||||
SnippetTextEdit: extHostTypes.SnippetTextEdit,
|
||||
SourceBreakpoint: extHostTypes.SourceBreakpoint,
|
||||
StandardTokenType: extHostTypes.StandardTokenType,
|
||||
StatusBarAlignment: extHostTypes.StatusBarAlignment,
|
||||
|
|
|
@ -1714,7 +1714,12 @@ export interface IInlineValueContextDto {
|
|||
export type ITypeHierarchyItemDto = Dto<TypeHierarchyItem>;
|
||||
|
||||
export interface IPasteEditDto {
|
||||
insertSnippet: string;
|
||||
insertText: string | { snippet: string };
|
||||
additionalEdit?: IWorkspaceEditDto;
|
||||
}
|
||||
|
||||
export interface IDocumentOnDropEditDto {
|
||||
insertText: string | { snippet: string };
|
||||
additionalEdit?: IWorkspaceEditDto;
|
||||
}
|
||||
|
||||
|
@ -1776,7 +1781,7 @@ export interface ExtHostLanguageFeaturesShape {
|
|||
$provideTypeHierarchySupertypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
|
||||
$provideTypeHierarchySubtypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<ITypeHierarchyItemDto[] | undefined>;
|
||||
$releaseTypeHierarchy(handle: number, sessionId: string): void;
|
||||
$provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined>;
|
||||
$provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: DataTransferDTO, token: CancellationToken): Promise<IDocumentOnDropEditDto | undefined>;
|
||||
}
|
||||
|
||||
export interface ExtHostQuickOpenShape {
|
||||
|
|
|
@ -34,7 +34,6 @@ import { StopWatch } from 'vs/base/common/stopwatch';
|
|||
import { isCancellationError, NotImplementedError } from 'vs/base/common/errors';
|
||||
import { raceCancellationError } from 'vs/base/common/async';
|
||||
import { isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
|
||||
// --- adapter
|
||||
|
||||
|
@ -524,7 +523,7 @@ class DocumentPasteEditProvider {
|
|||
}
|
||||
|
||||
return {
|
||||
insertSnippet: typeof edit.insertText === 'string' ? edit.insertText : edit.insertText.value,
|
||||
insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
|
||||
additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit) : undefined,
|
||||
};
|
||||
}
|
||||
|
@ -1798,7 +1797,7 @@ class DocumentOnDropEditAdapter {
|
|||
private readonly _handle: number,
|
||||
) { }
|
||||
|
||||
async provideDocumentOnDropEdits(requestId: number, uri: URI, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined> {
|
||||
async provideDocumentOnDropEdits(requestId: number, uri: URI, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IDocumentOnDropEditDto | undefined> {
|
||||
const doc = this._documents.getDocument(uri);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, async (index) => {
|
||||
|
@ -1809,7 +1808,10 @@ class DocumentOnDropEditAdapter {
|
|||
if (!edit) {
|
||||
return undefined;
|
||||
}
|
||||
return typeConvert.SnippetTextEdit.from(edit);
|
||||
return {
|
||||
insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
|
||||
additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit) : undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2453,7 +2455,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
|
|||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<Dto<languages.SnippetTextEdit> | undefined> {
|
||||
$provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IDocumentOnDropEditDto | undefined> {
|
||||
return this._withAdapter(handle, DocumentOnDropEditAdapter, adapter =>
|
||||
Promise.resolve(adapter.provideDocumentOnDropEdits(requestId, URI.revive(resource), position, dataTransferDto, token)), undefined, undefined);
|
||||
}
|
||||
|
|
|
@ -562,15 +562,6 @@ export namespace TextEdit {
|
|||
}
|
||||
}
|
||||
|
||||
export namespace SnippetTextEdit {
|
||||
export function from(edit: vscode.SnippetTextEdit): languages.SnippetTextEdit {
|
||||
return {
|
||||
range: Range.from(edit.range),
|
||||
snippet: edit.snippet.value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export namespace WorkspaceEdit {
|
||||
|
||||
export interface IVersionInformationProvider {
|
||||
|
|
|
@ -647,17 +647,6 @@ export class NotebookEdit implements vscode.NotebookEdit {
|
|||
}
|
||||
}
|
||||
|
||||
export class SnippetTextEdit implements vscode.SnippetTextEdit {
|
||||
|
||||
range: vscode.Range;
|
||||
snippet: vscode.SnippetString;
|
||||
|
||||
constructor(range: Range, snippet: SnippetString) {
|
||||
this.range = range;
|
||||
this.snippet = snippet;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IFileOperationOptions {
|
||||
overwrite?: boolean;
|
||||
ignoreIfExists?: boolean;
|
||||
|
|
|
@ -7,12 +7,6 @@ declare module 'vscode' {
|
|||
|
||||
// https://github.com/microsoft/vscode/issues/142990
|
||||
|
||||
export class SnippetTextEdit {
|
||||
snippet: SnippetString;
|
||||
range: Range;
|
||||
constructor(range: Range, snippet: SnippetString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider which handles dropping of resources into a text editor.
|
||||
*
|
||||
|
@ -27,10 +21,25 @@ declare module 'vscode' {
|
|||
* @param dataTransfer A {@link DataTransfer} object that holds data about what is being dragged and dropped.
|
||||
* @param token A cancellation token.
|
||||
*
|
||||
* @return A {@link SnippetTextEdit} or a thenable that resolves to such. The lack of a result can be
|
||||
* @return A {@link DocumentDropEdit} or a thenable that resolves to such. The lack of a result can be
|
||||
* signaled by returning `undefined` or `null`.
|
||||
*/
|
||||
provideDocumentOnDropEdits(document: TextDocument, position: Position, dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<SnippetTextEdit>;
|
||||
provideDocumentOnDropEdits(document: TextDocument, position: Position, dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<DocumentDropEdit>;
|
||||
}
|
||||
|
||||
/**
|
||||
* An edit operation applied on drop.
|
||||
*/
|
||||
export interface DocumentDropEdit {
|
||||
/**
|
||||
* The text or snippet to insert at the drop location.
|
||||
*/
|
||||
readonly insertText: string | SnippetString;
|
||||
|
||||
/**
|
||||
* An optional additional edit to apply on drop.
|
||||
*/
|
||||
readonly additionalEdit?: WorkspaceEdit;
|
||||
}
|
||||
|
||||
export namespace languages {
|
||||
|
|
Loading…
Reference in a new issue