mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 13:00:58 +00:00
Make sure drop edits are disposed of properly (#216084)
This commit is contained in:
parent
3ef8921a20
commit
290eb3df07
|
@ -2214,6 +2214,14 @@ export interface DocumentDropEdit {
|
|||
additionalEdit?: WorkspaceEdit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface DocumentDropEditsSession {
|
||||
edits: readonly DocumentDropEdit[];
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -2221,7 +2229,7 @@ export interface DocumentDropEditProvider {
|
|||
readonly id?: string;
|
||||
readonly dropMimeTypes?: readonly string[];
|
||||
|
||||
provideDocumentDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): ProviderResult<DocumentDropEdit[]>;
|
||||
provideDocumentDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): ProviderResult<DocumentDropEditsSession>;
|
||||
resolveDocumentDropEdit?(edit: DocumentDropEdit, token: CancellationToken): Promise<DocumentDropEdit>;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import { relativePath } from 'vs/base/common/resources';
|
|||
import { URI } from 'vs/base/common/uri';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { DocumentDropEdit, DocumentDropEditProvider, DocumentPasteContext, DocumentPasteEdit, DocumentPasteEditProvider, DocumentPasteEditsSession, DocumentPasteTriggerKind } from 'vs/editor/common/languages';
|
||||
import { DocumentDropEditProvider, DocumentDropEditsSession, DocumentPasteContext, DocumentPasteEdit, DocumentPasteEditProvider, DocumentPasteEditsSession, DocumentPasteTriggerKind } from 'vs/editor/common/languages';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
|
||||
import { localize } from 'vs/nls';
|
||||
|
@ -34,14 +34,20 @@ abstract class SimplePasteAndDropProvider implements DocumentDropEditProvider, D
|
|||
}
|
||||
|
||||
return {
|
||||
edits: [{ insertText: edit.insertText, title: edit.title, kind: edit.kind, handledMimeType: edit.handledMimeType, yieldTo: edit.yieldTo }],
|
||||
dispose() { },
|
||||
edits: [{ insertText: edit.insertText, title: edit.title, kind: edit.kind, handledMimeType: edit.handledMimeType, yieldTo: edit.yieldTo }]
|
||||
};
|
||||
}
|
||||
|
||||
async provideDocumentDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<DocumentDropEdit[] | undefined> {
|
||||
async provideDocumentDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<DocumentDropEditsSession | undefined> {
|
||||
const edit = await this.getEdit(dataTransfer, token);
|
||||
return edit ? [{ insertText: edit.insertText, title: edit.title, kind: edit.kind, handledMimeType: edit.handledMimeType, yieldTo: edit.yieldTo }] : undefined;
|
||||
if (!edit) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
edits: [{ insertText: edit.insertText, title: edit.title, kind: edit.kind, handledMimeType: edit.handledMimeType, yieldTo: edit.yieldTo }],
|
||||
dispose() { },
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract getEdit(dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined>;
|
||||
|
|
|
@ -7,7 +7,7 @@ import { coalesce } from 'vs/base/common/arrays';
|
|||
import { CancelablePromise, createCancelablePromise, raceCancellation } from 'vs/base/common/async';
|
||||
import { VSDataTransfer, matchesMimeType } from 'vs/base/common/dataTransfer';
|
||||
import { HierarchicalKind } from 'vs/base/common/hierarchicalKind';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { toExternalVSDataTransfer } from 'vs/editor/browser/dnd';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
|
@ -84,8 +84,9 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
|
|||
editor.setPosition(position);
|
||||
|
||||
const p = createCancelablePromise(async (token) => {
|
||||
const tokenSource = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value, undefined, token);
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const tokenSource = disposables.add(new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value, undefined, token));
|
||||
try {
|
||||
const ourDataTransfer = await this.extractDataTransferData(dragEvent);
|
||||
if (ourDataTransfer.size === 0 || tokenSource.token.isCancellationRequested) {
|
||||
|
@ -107,19 +108,19 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
|
|||
return provider.dropMimeTypes.some(mime => ourDataTransfer.matches(mime));
|
||||
});
|
||||
|
||||
const edits = await this.getDropEdits(providers, model, position, ourDataTransfer, tokenSource);
|
||||
const editSession = disposables.add(await this.getDropEdits(providers, model, position, ourDataTransfer, tokenSource));
|
||||
if (tokenSource.token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (edits.length) {
|
||||
const activeEditIndex = this.getInitialActiveEditIndex(model, edits);
|
||||
if (editSession.edits.length) {
|
||||
const activeEditIndex = this.getInitialActiveEditIndex(model, editSession.edits);
|
||||
const canShowWidget = editor.getOption(EditorOption.dropIntoEditor).showDropSelector === 'afterDrop';
|
||||
// Pass in the parent token here as it tracks cancelling the entire drop operation
|
||||
await this._postDropWidgetManager.applyEditAndShowIfNeeded([Range.fromPositions(position)], { activeEditIndex, allEdits: edits }, canShowWidget, async edit => edit, token);
|
||||
await this._postDropWidgetManager.applyEditAndShowIfNeeded([Range.fromPositions(position)], { activeEditIndex, allEdits: editSession.edits }, canShowWidget, async edit => edit, token);
|
||||
}
|
||||
} finally {
|
||||
tokenSource.dispose();
|
||||
disposables.dispose();
|
||||
if (this._currentOperation === p) {
|
||||
this._currentOperation = undefined;
|
||||
}
|
||||
|
@ -131,10 +132,15 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
|
|||
}
|
||||
|
||||
private async getDropEdits(providers: readonly DocumentDropEditProvider[], model: ITextModel, position: IPosition, dataTransfer: VSDataTransfer, tokenSource: EditorStateCancellationTokenSource) {
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const results = await raceCancellation(Promise.all(providers.map(async provider => {
|
||||
try {
|
||||
const edits = await provider.provideDocumentDropEdits(model, position, dataTransfer, tokenSource.token);
|
||||
return edits?.map(edit => ({ ...edit, providerId: provider.id }));
|
||||
if (edits) {
|
||||
disposables.add(edits);
|
||||
}
|
||||
return edits?.edits.map(edit => ({ ...edit, providerId: provider.id }));
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
@ -142,7 +148,10 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
|
|||
})), tokenSource.token);
|
||||
|
||||
const edits = coalesce(results ?? []).flat();
|
||||
return sortEditsByYieldTo(edits);
|
||||
return {
|
||||
edits: sortEditsByYieldTo(edits),
|
||||
dispose: () => disposables.dispose()
|
||||
};
|
||||
}
|
||||
|
||||
private getInitialActiveEditIndex(model: ITextModel, edits: ReadonlyArray<DocumentDropEdit & { readonly providerId?: string }>) {
|
||||
|
|
|
@ -1124,7 +1124,7 @@ class MainThreadDocumentOnDropEditProvider implements languages.DocumentDropEdit
|
|||
}
|
||||
}
|
||||
|
||||
async provideDocumentDropEdits(model: ITextModel, position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<languages.DocumentDropEdit[] | undefined> {
|
||||
async provideDocumentDropEdits(model: ITextModel, position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<languages.DocumentDropEditsSession | undefined> {
|
||||
const request = this.dataTransfers.add(dataTransfer);
|
||||
try {
|
||||
const dataTransferDto = await typeConvert.DataTransfer.from(dataTransfer);
|
||||
|
@ -1137,14 +1137,19 @@ class MainThreadDocumentOnDropEditProvider implements languages.DocumentDropEdit
|
|||
return;
|
||||
}
|
||||
|
||||
return edits.map(edit => {
|
||||
return {
|
||||
...edit,
|
||||
yieldTo: edit.yieldTo?.map(x => ({ kind: new HierarchicalKind(x) })),
|
||||
kind: edit.kind ? new HierarchicalKind(edit.kind) : undefined,
|
||||
additionalEdit: reviveWorkspaceEditDto(edit.additionalEdit, this._uriIdentService, dataId => this.resolveDocumentOnDropFileData(request.id, dataId)),
|
||||
};
|
||||
});
|
||||
return {
|
||||
edits: edits.map(edit => {
|
||||
return {
|
||||
...edit,
|
||||
yieldTo: edit.yieldTo?.map(x => ({ kind: new HierarchicalKind(x) })),
|
||||
kind: edit.kind ? new HierarchicalKind(edit.kind) : undefined,
|
||||
additionalEdit: reviveWorkspaceEditDto(edit.additionalEdit, this._uriIdentService, dataId => this.resolveDocumentOnDropFileData(request.id, dataId)),
|
||||
};
|
||||
}),
|
||||
dispose: () => {
|
||||
this._proxy.$releaseDocumentOnDropEdits(this._handle, request.id);
|
||||
},
|
||||
};
|
||||
} finally {
|
||||
request.dispose();
|
||||
}
|
||||
|
|
|
@ -2192,6 +2192,7 @@ export interface ExtHostLanguageFeaturesShape {
|
|||
$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<IDocumentDropEditDto[] | undefined>;
|
||||
$releaseDocumentOnDropEdits(handle: number, cacheId: number): void;
|
||||
$provideMappedEdits(handle: number, document: UriComponents, codeBlocks: string[], context: IMappedEditsContextDto, token: CancellationToken): Promise<IWorkspaceEditDto | null>;
|
||||
$provideInlineEdit(handle: number, document: UriComponents, context: languages.IInlineEditContext, token: CancellationToken): Promise<IdentifiableInlineEdit | undefined>;
|
||||
$freeInlineEdit(handle: number, pid: number): void;
|
||||
|
|
|
@ -2806,7 +2806,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
|
|||
return this._withAdapter(handle, DocumentDropEditAdapter, adapter => adapter.resolveDropEdit(id, token), {}, undefined);
|
||||
}
|
||||
|
||||
$releaseDropEdits(handle: number, cacheId: number): void {
|
||||
$releaseDocumentOnDropEdits(handle: number, cacheId: number): void {
|
||||
this._withAdapter(handle, DocumentDropEditAdapter, adapter => Promise.resolve(adapter.releaseDropEdits(cacheId)), undefined, undefined);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue