From 2d28bf82a002b7a3e0cec33874f94658add029a3 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 14 Jan 2022 15:31:50 +0100 Subject: [PATCH 1/6] Enable resourceurls --- src/vs/workbench/browser/dnd.ts | 32 +++++++++++++++++-- .../browser/parts/editor/editorDropTarget.ts | 26 +++++++++++++-- .../workbench/browser/parts/views/treeView.ts | 5 ++- .../vscode.proposed.treeViewDragAndDrop.d.ts | 3 ++ 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index bb7117b98cd95..f0c4dc9fbb3ac 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -33,6 +33,7 @@ import { parse, stringify } from 'vs/base/common/marshalling'; import { ILabelService } from 'vs/platform/label/common/label'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { ITreeDataTransfer } from 'vs/workbench/common/views'; //#region Editor / Resources DND @@ -46,6 +47,11 @@ export class DraggedEditorGroupIdentifier { constructor(readonly identifier: GroupIdentifier) { } } +export class DraggedExtensionTreeItemsIdentifier { + + constructor(readonly identifier: string) { } +} + export const CodeDataTransfers = { EDITORS: 'CodeEditors', FILES: 'CodeFiles' @@ -130,6 +136,28 @@ export function extractEditorsDropData(e: DragEvent): Array> { + const editors: IDraggedResourceEditorInput[] = []; + // Data Transfer: Resources + const resourcesKey = DataTransfers.RESOURCES.toLowerCase(); + if (dataTransfer.has(resourcesKey)) { + try { + const rawResourcesData = await dataTransfer.get(resourcesKey)?.asString(); + if (rawResourcesData) { + const rawResourceList = JSON.parse(rawResourcesData); + for (const resourceRaw of rawResourceList) { + if (resourceRaw.indexOf(':') > 0) { // mitigate https://github.com/microsoft/vscode/issues/124946 + editors.push({ resource: URI.parse(resourceRaw) }); + } + } + } + } catch (error) { + // Invalid transfer + } + } + return editors; +} + export interface IFileDropData { name: string; data: VSBuffer; @@ -195,8 +223,8 @@ export class ResourcesDropHandler { ) { } - async handleDrop(event: DragEvent, resolveTargetGroup: () => IEditorGroup | undefined, afterDrop: (targetGroup: IEditorGroup | undefined) => void, targetIndex?: number): Promise { - const editors = extractEditorsDropData(event); + async handleDrop(event: DragEvent | ITreeDataTransfer, resolveTargetGroup: () => IEditorGroup | undefined, afterDrop: (targetGroup: IEditorGroup | undefined) => void, targetIndex?: number): Promise { + const editors = event instanceof DragEvent ? extractEditorsDropData(event) : await extractTreeDropData(event); if (!editors.length) { return; } diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index 71c66435f04d1..66376860ed988 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/editordroptarget'; -import { LocalSelectionTransfer, DraggedEditorIdentifier, ResourcesDropHandler, DraggedEditorGroupIdentifier, DragAndDropObserver, containsDragType, CodeDataTransfers, extractFilesDropData } from 'vs/workbench/browser/dnd'; +import { LocalSelectionTransfer, DraggedEditorIdentifier, ResourcesDropHandler, DraggedEditorGroupIdentifier, DragAndDropObserver, containsDragType, CodeDataTransfers, extractFilesDropData, DraggedExtensionTreeItemsIdentifier } from 'vs/workbench/browser/dnd'; import { addDisposableListener, EventType, EventHelper, isAncestor } from 'vs/base/browser/dom'; import { IEditorGroupsAccessor, IEditorGroupView, fillActiveEditorViewState } from 'vs/workbench/browser/parts/editor/editor'; import { EDITOR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; @@ -21,6 +21,8 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic import { assertIsDefined, assertAllDefined } from 'vs/base/common/types'; import { Schemas } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; +import { ITreeViewsDragAndDropService } from 'vs/workbench/services/views/common/treeViewsDragAndDropService'; +import { ITreeDataTransfer } from 'vs/workbench/common/views'; interface IDropOperation { splitDirection?: GroupDirection; @@ -40,6 +42,7 @@ class DropOverlay extends Themable { private readonly editorTransfer = LocalSelectionTransfer.getInstance(); private readonly groupTransfer = LocalSelectionTransfer.getInstance(); + private readonly treeItemsTransfer = LocalSelectionTransfer.getInstance(); constructor( private accessor: IEditorGroupsAccessor, @@ -47,7 +50,8 @@ class DropOverlay extends Themable { @IThemeService themeService: IThemeService, @IInstantiationService private instantiationService: IInstantiationService, @IEditorService private readonly editorService: IEditorService, - @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService + @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, + @ITreeViewsDragAndDropService private readonly treeViewsDragAndDropService: ITreeViewsDragAndDropService ) { super(themeService); @@ -292,6 +296,24 @@ class DropOverlay extends Themable { } } + // Check for tree items + else if (this.treeItemsTransfer.hasData(DraggedExtensionTreeItemsIdentifier.prototype)) { + const data = this.treeItemsTransfer.getData(DraggedExtensionTreeItemsIdentifier.prototype); + if (Array.isArray(data)) { + const treeData = Promise.all( + data.map(id => this.treeViewsDragAndDropService.removeDragOperationTransfer(id.identifier))); + treeData.then(dataTransferItems => { + const dropHandler = this.instantiationService.createInstance(ResourcesDropHandler, { allowWorkspaceOpen: true /* open workspace instead of file if dropped */ }); + dataTransferItems.forEach(dataTransferItem => { + if (dataTransferItem) { + dropHandler.handleDrop(dataTransferItem, () => ensureTargetGroup(), targetGroup => targetGroup?.focus()); + } + }); + }); + } + this.treeItemsTransfer.clearData(DraggedExtensionTreeItemsIdentifier.prototype); + } + // Web: check for file transfer else if (isWeb && containsDragType(event, DataTransfers.FILES)) { let targetGroup: IEditorGroupView | undefined = undefined; diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index 8d4c90f4a5b0c..85a05c10aee50 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -57,7 +57,7 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance import { Command } from 'vs/editor/common/languages'; import { isCancellationError } from 'vs/base/common/errors'; import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; -import { CodeDataTransfers, fillEditorsDragData } from 'vs/workbench/browser/dnd'; +import { CodeDataTransfers, DraggedExtensionTreeItemsIdentifier, fillEditorsDragData, LocalSelectionTransfer } from 'vs/workbench/browser/dnd'; import { Schemas } from 'vs/base/common/network'; import { ITreeViewsDragAndDropService } from 'vs/workbench/services/views/common/treeViewsDragAndDropService'; import { generateUuid } from 'vs/base/common/uuid'; @@ -1241,6 +1241,8 @@ const TREE_DRAG_UUID_MIME = 'tree-dnd'; export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop { private readonly treeMimeType: string; + private readonly treeItemsTransfer = LocalSelectionTransfer.getInstance(); + constructor( private readonly treeId: string, @ILabelService private readonly labelService: ILabelService, @@ -1262,6 +1264,7 @@ export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop { const uuid = generateUuid(); this.treeViewsDragAndDropService.addDragOperationTransfer(uuid, this.dndController.handleDrag(itemHandles, uuid)); originalEvent.dataTransfer.setData(TREE_DRAG_UUID_MIME, uuid); + this.treeItemsTransfer.setData([new DraggedExtensionTreeItemsIdentifier(uuid)], DraggedExtensionTreeItemsIdentifier.prototype); } private addResourceInfoToTransfer(originalEvent: DragEvent, resources: URI[]) { diff --git a/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts b/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts index f135fa73a8d57..7f4d5bac67fde 100644 --- a/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts +++ b/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts @@ -102,6 +102,9 @@ declare module 'vscode' { * When the items are dropped on **another tree item** in **the same tree**, your `TreeDataTransferItem` objects * will be preserved. See the documentation for `TreeDataTransferItem` for how best to take advantage of this. * + * To add a data transfer item that can be dragged into the editor, use the application specific mime type "resourceurls". + * The data for "resourceurls" should be an array of `toString()`ed Uris. + * * @param source The source items for the drag and drop operation. * @param treeDataTransfer The data transfer associated with this drag. */ From 70fce30df4f264242fac32d1932ff7267243ad8a Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Fri, 21 Jan 2022 11:24:37 +0100 Subject: [PATCH 2/6] Add selection to resourceurls from trees --- src/vs/editor/browser/services/openerService.ts | 14 +++----------- src/vs/platform/opener/common/opener.ts | 14 ++++++++++++++ src/vs/workbench/browser/dnd.ts | 11 +++++++++-- .../vscode.proposed.treeViewDragAndDrop.d.ts | 3 ++- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index ffb075f20b51d..7c671a583733d 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -15,7 +15,7 @@ import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { EditorOpenContext } from 'vs/platform/editor/common/editor'; -import { IExternalOpener, IExternalUriResolver, IOpener, IOpenerService, IResolvedExternalUri, IValidator, matchesScheme, matchesSomeScheme, OpenOptions, ResolveExternalUriOptions } from 'vs/platform/opener/common/opener'; +import { IExternalOpener, IExternalUriResolver, IOpener, IOpenerService, IResolvedExternalUri, IValidator, matchesScheme, matchesSomeScheme, OpenOptions, ResolveExternalUriOptions, selectionFragment } from 'vs/platform/opener/common/opener'; class CommandOpener implements IOpener { @@ -62,16 +62,8 @@ class EditorOpener implements IOpener { if (typeof target === 'string') { target = URI.parse(target); } - let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; - const match = /^L?(\d+)(?:,(\d+))?/.exec(target.fragment); - if (match) { - // support file:///some/file.js#73,84 - // support file:///some/file.js#L73 - selection = { - startLineNumber: parseInt(match[1]), - startColumn: match[2] ? parseInt(match[2]) : 1 - }; - // remove fragment + const selection: { startLineNumber: number; startColumn: number; } | undefined = selectionFragment(target); + if (selection) { target = target.with({ fragment: '' }); } diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index ea79903e8a959..f71caa5927953 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -136,3 +136,17 @@ export function matchesScheme(target: URI | string, scheme: string): boolean { export function matchesSomeScheme(target: URI | string, ...schemes: string[]): boolean { return schemes.some(scheme => matchesScheme(target, scheme)); } + +export function selectionFragment(target: URI): { startLineNumber: number; startColumn: number; } | undefined { + let selection: { startLineNumber: number; startColumn: number; } | undefined = undefined; + const match = /^L?(\d+)(?:,(\d+))?/.exec(target.fragment); + if (match) { + // support file:///some/file.js#73,84 + // support file:///some/file.js#L73 + selection = { + startLineNumber: parseInt(match[1]), + startColumn: match[2] ? parseInt(match[2]) : 1 + }; + } + return selection; +} diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index f0c4dc9fbb3ac..9bfc69dc16cd3 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -34,6 +34,7 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { withNullAsUndefined } from 'vs/base/common/types'; import { ITreeDataTransfer } from 'vs/workbench/common/views'; +import { selectionFragment } from 'vs/platform/opener/common/opener'; //#region Editor / Resources DND @@ -138,8 +139,8 @@ export function extractEditorsDropData(e: DragEvent): Array> { const editors: IDraggedResourceEditorInput[] = []; - // Data Transfer: Resources const resourcesKey = DataTransfers.RESOURCES.toLowerCase(); + // Data Transfer: Resources if (dataTransfer.has(resourcesKey)) { try { const rawResourcesData = await dataTransfer.get(resourcesKey)?.asString(); @@ -147,7 +148,13 @@ export async function extractTreeDropData(dataTransfer: ITreeDataTransfer): Prom const rawResourceList = JSON.parse(rawResourcesData); for (const resourceRaw of rawResourceList) { if (resourceRaw.indexOf(':') > 0) { // mitigate https://github.com/microsoft/vscode/issues/124946 - editors.push({ resource: URI.parse(resourceRaw) }); + const resource = URI.parse(resourceRaw); + editors.push({ + resource, + options: { + selection: selectionFragment(resource) + } + }); } } } diff --git a/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts b/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts index 7f4d5bac67fde..6d9151ded01d5 100644 --- a/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts +++ b/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts @@ -103,7 +103,8 @@ declare module 'vscode' { * will be preserved. See the documentation for `TreeDataTransferItem` for how best to take advantage of this. * * To add a data transfer item that can be dragged into the editor, use the application specific mime type "resourceurls". - * The data for "resourceurls" should be an array of `toString()`ed Uris. + * The data for "resourceurls" should be an array of `toString()`ed Uris. To specify a cursor position in the file, + * set the Uri's fragment to `L3,5`, where 3 is the line number and 5 is the column number. * * @param source The source items for the drag and drop operation. * @param treeDataTransfer The data transfer associated with this drag. From 40740eb4db88e8557856c69b52c4623c0bb40e03 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 24 Jan 2022 15:29:11 +0100 Subject: [PATCH 3/6] Rename identifier --- src/vs/workbench/browser/dnd.ts | 2 +- .../workbench/browser/parts/editor/editorDropTarget.ts | 10 +++++----- src/vs/workbench/browser/parts/views/treeView.ts | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 9bfc69dc16cd3..55c4c4cc911c3 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -48,7 +48,7 @@ export class DraggedEditorGroupIdentifier { constructor(readonly identifier: GroupIdentifier) { } } -export class DraggedExtensionTreeItemsIdentifier { +export class DraggedTreeItemsIdentifier { constructor(readonly identifier: string) { } } diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index 66376860ed988..4ac1943e8b552 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/editordroptarget'; -import { LocalSelectionTransfer, DraggedEditorIdentifier, ResourcesDropHandler, DraggedEditorGroupIdentifier, DragAndDropObserver, containsDragType, CodeDataTransfers, extractFilesDropData, DraggedExtensionTreeItemsIdentifier } from 'vs/workbench/browser/dnd'; +import { LocalSelectionTransfer, DraggedEditorIdentifier, ResourcesDropHandler, DraggedEditorGroupIdentifier, DragAndDropObserver, containsDragType, CodeDataTransfers, extractFilesDropData, DraggedTreeItemsIdentifier } from 'vs/workbench/browser/dnd'; import { addDisposableListener, EventType, EventHelper, isAncestor } from 'vs/base/browser/dom'; import { IEditorGroupsAccessor, IEditorGroupView, fillActiveEditorViewState } from 'vs/workbench/browser/parts/editor/editor'; import { EDITOR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; @@ -42,7 +42,7 @@ class DropOverlay extends Themable { private readonly editorTransfer = LocalSelectionTransfer.getInstance(); private readonly groupTransfer = LocalSelectionTransfer.getInstance(); - private readonly treeItemsTransfer = LocalSelectionTransfer.getInstance(); + private readonly treeItemsTransfer = LocalSelectionTransfer.getInstance(); constructor( private accessor: IEditorGroupsAccessor, @@ -297,8 +297,8 @@ class DropOverlay extends Themable { } // Check for tree items - else if (this.treeItemsTransfer.hasData(DraggedExtensionTreeItemsIdentifier.prototype)) { - const data = this.treeItemsTransfer.getData(DraggedExtensionTreeItemsIdentifier.prototype); + else if (this.treeItemsTransfer.hasData(DraggedTreeItemsIdentifier.prototype)) { + const data = this.treeItemsTransfer.getData(DraggedTreeItemsIdentifier.prototype); if (Array.isArray(data)) { const treeData = Promise.all( data.map(id => this.treeViewsDragAndDropService.removeDragOperationTransfer(id.identifier))); @@ -311,7 +311,7 @@ class DropOverlay extends Themable { }); }); } - this.treeItemsTransfer.clearData(DraggedExtensionTreeItemsIdentifier.prototype); + this.treeItemsTransfer.clearData(DraggedTreeItemsIdentifier.prototype); } // Web: check for file transfer diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index 85a05c10aee50..909e35cf99734 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -57,7 +57,7 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance import { Command } from 'vs/editor/common/languages'; import { isCancellationError } from 'vs/base/common/errors'; import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; -import { CodeDataTransfers, DraggedExtensionTreeItemsIdentifier, fillEditorsDragData, LocalSelectionTransfer } from 'vs/workbench/browser/dnd'; +import { CodeDataTransfers, DraggedTreeItemsIdentifier, fillEditorsDragData, LocalSelectionTransfer } from 'vs/workbench/browser/dnd'; import { Schemas } from 'vs/base/common/network'; import { ITreeViewsDragAndDropService } from 'vs/workbench/services/views/common/treeViewsDragAndDropService'; import { generateUuid } from 'vs/base/common/uuid'; @@ -1241,7 +1241,7 @@ const TREE_DRAG_UUID_MIME = 'tree-dnd'; export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop { private readonly treeMimeType: string; - private readonly treeItemsTransfer = LocalSelectionTransfer.getInstance(); + private readonly treeItemsTransfer = LocalSelectionTransfer.getInstance(); constructor( private readonly treeId: string, @@ -1264,7 +1264,7 @@ export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop { const uuid = generateUuid(); this.treeViewsDragAndDropService.addDragOperationTransfer(uuid, this.dndController.handleDrag(itemHandles, uuid)); originalEvent.dataTransfer.setData(TREE_DRAG_UUID_MIME, uuid); - this.treeItemsTransfer.setData([new DraggedExtensionTreeItemsIdentifier(uuid)], DraggedExtensionTreeItemsIdentifier.prototype); + this.treeItemsTransfer.setData([new DraggedTreeItemsIdentifier(uuid)], DraggedTreeItemsIdentifier.prototype); } private addResourceInfoToTransfer(originalEvent: DragEvent, resources: URI[]) { From 825029610fa0aa4c678764156b8579b9c7521096 Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Mon, 24 Jan 2022 16:26:09 +0100 Subject: [PATCH 4/6] Respond to PR feedback --- src/vs/workbench/browser/dnd.ts | 48 +++++++++---------- .../browser/parts/editor/editorDropTarget.ts | 17 +++++-- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 55c4c4cc911c3..a7945aac69599 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -63,6 +63,26 @@ export interface IDraggedResourceEditorInput extends IBaseTextResourceEditorInpu isExternal?: boolean; } + +function createDraggedEditorInputFromRawResourcesData(rawResourcesData: string | undefined): IDraggedResourceEditorInput[] { + const editors: IDraggedResourceEditorInput[] = []; + if (rawResourcesData) { + const resourcesRaw: string[] = JSON.parse(rawResourcesData); + for (const resourceRaw of resourcesRaw) { + if (resourceRaw.indexOf(':') > 0) { // mitigate https://github.com/microsoft/vscode/issues/124946 + const resource = URI.parse(resourceRaw); + editors.push({ + resource, + options: { + selection: selectionFragment(resource) + } + }); + } + } + } + return editors; +} + export function extractEditorsDropData(e: DragEvent): Array { const editors: IDraggedResourceEditorInput[] = []; if (e.dataTransfer && e.dataTransfer.types.length > 0) { @@ -81,14 +101,7 @@ export function extractEditorsDropData(e: DragEvent): Array 0) { // mitigate https://github.com/microsoft/vscode/issues/124946 - editors.push({ resource: URI.parse(resourceRaw) }); - } - } - } + editors.push(...createDraggedEditorInputFromRawResourcesData(rawResourcesData)); } catch (error) { // Invalid transfer } @@ -144,20 +157,7 @@ export async function extractTreeDropData(dataTransfer: ITreeDataTransfer): Prom if (dataTransfer.has(resourcesKey)) { try { const rawResourcesData = await dataTransfer.get(resourcesKey)?.asString(); - if (rawResourcesData) { - const rawResourceList = JSON.parse(rawResourcesData); - for (const resourceRaw of rawResourceList) { - if (resourceRaw.indexOf(':') > 0) { // mitigate https://github.com/microsoft/vscode/issues/124946 - const resource = URI.parse(resourceRaw); - editors.push({ - resource, - options: { - selection: selectionFragment(resource) - } - }); - } - } - } + editors.push(...createDraggedEditorInputFromRawResourcesData(rawResourcesData)); } catch (error) { // Invalid transfer } @@ -230,8 +230,8 @@ export class ResourcesDropHandler { ) { } - async handleDrop(event: DragEvent | ITreeDataTransfer, resolveTargetGroup: () => IEditorGroup | undefined, afterDrop: (targetGroup: IEditorGroup | undefined) => void, targetIndex?: number): Promise { - const editors = event instanceof DragEvent ? extractEditorsDropData(event) : await extractTreeDropData(event); + async handleDrop(event: DragEvent, resolveTargetGroup: () => IEditorGroup | undefined, afterDrop: (targetGroup: IEditorGroup | undefined) => void, targetIndex?: number): Promise { + const editors = extractEditorsDropData(event); if (!editors.length) { return; } diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index 4ac1943e8b552..9b710a04524a7 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/editordroptarget'; -import { LocalSelectionTransfer, DraggedEditorIdentifier, ResourcesDropHandler, DraggedEditorGroupIdentifier, DragAndDropObserver, containsDragType, CodeDataTransfers, extractFilesDropData, DraggedTreeItemsIdentifier } from 'vs/workbench/browser/dnd'; +import { LocalSelectionTransfer, DraggedEditorIdentifier, ResourcesDropHandler, DraggedEditorGroupIdentifier, DragAndDropObserver, containsDragType, CodeDataTransfers, extractFilesDropData, DraggedTreeItemsIdentifier, extractTreeDropData } from 'vs/workbench/browser/dnd'; import { addDisposableListener, EventType, EventHelper, isAncestor } from 'vs/base/browser/dom'; import { IEditorGroupsAccessor, IEditorGroupView, fillActiveEditorViewState } from 'vs/workbench/browser/parts/editor/editor'; import { EDITOR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; @@ -303,12 +303,19 @@ class DropOverlay extends Themable { const treeData = Promise.all( data.map(id => this.treeViewsDragAndDropService.removeDragOperationTransfer(id.identifier))); treeData.then(dataTransferItems => { - const dropHandler = this.instantiationService.createInstance(ResourcesDropHandler, { allowWorkspaceOpen: true /* open workspace instead of file if dropped */ }); - dataTransferItems.forEach(dataTransferItem => { + return Promise.all(dataTransferItems.map(async (dataTransferItem) => { if (dataTransferItem) { - dropHandler.handleDrop(dataTransferItem, () => ensureTargetGroup(), targetGroup => targetGroup?.focus()); + const treeDropData = await extractTreeDropData(dataTransferItem); + await this.editorService.openEditors(treeDropData.map(editor => ({ + ...editor, + resource: editor.resource, + options: { + ...editor.options, + pinned: true, + } + })), ensureTargetGroup(), { validateTrust: true }); } - }); + })); }); } this.treeItemsTransfer.clearData(DraggedTreeItemsIdentifier.prototype); From c7c48b8ff91af3c4f5344d56a74488efdcc83c5c Mon Sep 17 00:00:00 2001 From: Alex Ross Date: Tue, 25 Jan 2022 13:44:37 +0100 Subject: [PATCH 5/6] Do not loop opver openEditors --- .../browser/parts/editor/editorDropTarget.ts | 49 ++++++++++--------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index 9b710a04524a7..f71268d543ac5 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -10,7 +10,7 @@ import { IEditorGroupsAccessor, IEditorGroupView, fillActiveEditorViewState } fr import { EDITOR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme'; import { IThemeService, Themable } from 'vs/platform/theme/common/themeService'; import { activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; -import { IEditorIdentifier, EditorInputCapabilities } from 'vs/workbench/common/editor'; +import { IEditorIdentifier, EditorInputCapabilities, IUntypedEditorInput } from 'vs/workbench/common/editor'; import { isMacintosh, isWeb } from 'vs/base/common/platform'; import { GroupDirection, IEditorGroupsService, MergeGroupMode } from 'vs/workbench/services/editor/common/editorGroupsService'; import { toDisposable } from 'vs/base/common/lifecycle'; @@ -206,6 +206,31 @@ class DropOverlay extends Themable { return undefined; } + private async handleTreeDrop(ensureTargetGroup: () => IEditorGroupView): Promise { + const data = this.treeItemsTransfer.getData(DraggedTreeItemsIdentifier.prototype); + if (Array.isArray(data)) { + const editors: IUntypedEditorInput[] = []; + for (const id of data) { + const dataTransferItem = await this.treeViewsDragAndDropService.removeDragOperationTransfer(id.identifier); + if (dataTransferItem) { + const extractedDropData = await extractTreeDropData(dataTransferItem); + editors.push(...extractedDropData.map(editor => { + return { + ...editor, + resource: editor.resource, + options: { + ...editor.options, + pinned: true, + } + }; + })); + } + } + await this.editorService.openEditors(editors, ensureTargetGroup(), { validateTrust: true }); + } + this.treeItemsTransfer.clearData(DraggedTreeItemsIdentifier.prototype); + } + private handleDrop(event: DragEvent, splitDirection?: GroupDirection): void { // Determine target group @@ -298,27 +323,7 @@ class DropOverlay extends Themable { // Check for tree items else if (this.treeItemsTransfer.hasData(DraggedTreeItemsIdentifier.prototype)) { - const data = this.treeItemsTransfer.getData(DraggedTreeItemsIdentifier.prototype); - if (Array.isArray(data)) { - const treeData = Promise.all( - data.map(id => this.treeViewsDragAndDropService.removeDragOperationTransfer(id.identifier))); - treeData.then(dataTransferItems => { - return Promise.all(dataTransferItems.map(async (dataTransferItem) => { - if (dataTransferItem) { - const treeDropData = await extractTreeDropData(dataTransferItem); - await this.editorService.openEditors(treeDropData.map(editor => ({ - ...editor, - resource: editor.resource, - options: { - ...editor.options, - pinned: true, - } - })), ensureTargetGroup(), { validateTrust: true }); - } - })); - }); - } - this.treeItemsTransfer.clearData(DraggedTreeItemsIdentifier.prototype); + this.handleTreeDrop(ensureTargetGroup); } // Web: check for file transfer From 711d70b210aa6159f11602f5b7f395e65832b1fc Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 25 Jan 2022 14:15:07 +0100 Subject: [PATCH 6/6] :lipstick: --- src/vs/workbench/browser/dnd.ts | 44 +++++++++------- .../browser/parts/editor/editorDropTarget.ts | 52 +++++++++---------- 2 files changed, 49 insertions(+), 47 deletions(-) diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index a7945aac69599..0953de6627c2f 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -63,26 +63,6 @@ export interface IDraggedResourceEditorInput extends IBaseTextResourceEditorInpu isExternal?: boolean; } - -function createDraggedEditorInputFromRawResourcesData(rawResourcesData: string | undefined): IDraggedResourceEditorInput[] { - const editors: IDraggedResourceEditorInput[] = []; - if (rawResourcesData) { - const resourcesRaw: string[] = JSON.parse(rawResourcesData); - for (const resourceRaw of resourcesRaw) { - if (resourceRaw.indexOf(':') > 0) { // mitigate https://github.com/microsoft/vscode/issues/124946 - const resource = URI.parse(resourceRaw); - editors.push({ - resource, - options: { - selection: selectionFragment(resource) - } - }); - } - } - } - return editors; -} - export function extractEditorsDropData(e: DragEvent): Array { const editors: IDraggedResourceEditorInput[] = []; if (e.dataTransfer && e.dataTransfer.types.length > 0) { @@ -147,12 +127,35 @@ export function extractEditorsDropData(e: DragEvent): Array 0) { // mitigate https://github.com/microsoft/vscode/issues/124946 + const resource = URI.parse(resourceRaw); + editors.push({ + resource, + options: { + selection: selectionFragment(resource) + } + }); + } + } + } + return editors; } export async function extractTreeDropData(dataTransfer: ITreeDataTransfer): Promise> { const editors: IDraggedResourceEditorInput[] = []; const resourcesKey = DataTransfers.RESOURCES.toLowerCase(); + // Data Transfer: Resources if (dataTransfer.has(resourcesKey)) { try { @@ -162,6 +165,7 @@ export async function extractTreeDropData(dataTransfer: ITreeDataTransfer): Prom // Invalid transfer } } + return editors; } diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index f71268d543ac5..d3eb933b0a1dd 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -206,32 +206,7 @@ class DropOverlay extends Themable { return undefined; } - private async handleTreeDrop(ensureTargetGroup: () => IEditorGroupView): Promise { - const data = this.treeItemsTransfer.getData(DraggedTreeItemsIdentifier.prototype); - if (Array.isArray(data)) { - const editors: IUntypedEditorInput[] = []; - for (const id of data) { - const dataTransferItem = await this.treeViewsDragAndDropService.removeDragOperationTransfer(id.identifier); - if (dataTransferItem) { - const extractedDropData = await extractTreeDropData(dataTransferItem); - editors.push(...extractedDropData.map(editor => { - return { - ...editor, - resource: editor.resource, - options: { - ...editor.options, - pinned: true, - } - }; - })); - } - } - await this.editorService.openEditors(editors, ensureTargetGroup(), { validateTrust: true }); - } - this.treeItemsTransfer.clearData(DraggedTreeItemsIdentifier.prototype); - } - - private handleDrop(event: DragEvent, splitDirection?: GroupDirection): void { + private async handleDrop(event: DragEvent, splitDirection?: GroupDirection): Promise { // Determine target group const ensureTargetGroup = () => { @@ -323,7 +298,30 @@ class DropOverlay extends Themable { // Check for tree items else if (this.treeItemsTransfer.hasData(DraggedTreeItemsIdentifier.prototype)) { - this.handleTreeDrop(ensureTargetGroup); + const data = this.treeItemsTransfer.getData(DraggedTreeItemsIdentifier.prototype); + if (Array.isArray(data)) { + const editors: IUntypedEditorInput[] = []; + for (const id of data) { + const dataTransferItem = await this.treeViewsDragAndDropService.removeDragOperationTransfer(id.identifier); + if (dataTransferItem) { + const extractedDropData = await extractTreeDropData(dataTransferItem); + editors.push(...extractedDropData.map(editor => { + return { + ...editor, + resource: editor.resource, + options: { + ...editor.options, + pinned: true + } + }; + })); + } + } + + this.editorService.openEditors(editors, ensureTargetGroup(), { validateTrust: true }); + } + + this.treeItemsTransfer.clearData(DraggedTreeItemsIdentifier.prototype); } // Web: check for file transfer