diff --git a/src/vs/base/common/mime.ts b/src/vs/base/common/mime.ts index f77f51c713c..5c0b6d6054a 100644 --- a/src/vs/base/common/mime.ts +++ b/src/vs/base/common/mime.ts @@ -11,6 +11,7 @@ export namespace Mimes { export const unknown = 'application/unknown'; export const markdown = 'text/markdown'; export const latex = 'text/latex'; + export const uriList = 'text/uri-list'; } interface MapExtToMediaMimes { diff --git a/src/vs/workbench/api/browser/mainThreadTreeViews.ts b/src/vs/workbench/api/browser/mainThreadTreeViews.ts index 4ea3a5b2830..1ed3205e18d 100644 --- a/src/vs/workbench/api/browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/browser/mainThreadTreeViews.ts @@ -33,14 +33,14 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews); } - async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[] | undefined; dragMimeTypes: string[] | undefined; hasHandleDrag: boolean }): Promise { + async $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[]; dragMimeTypes: string[]; hasHandleDrag: boolean }): Promise { this.logService.trace('MainThreadTreeViews#$registerTreeViewDataProvider', treeViewId, options); this.extensionService.whenInstalledExtensionsRegistered().then(() => { const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService); this._dataProviders.set(treeViewId, dataProvider); const dndController = options.dropMimeTypes - ? new TreeViewDragAndDropController(treeViewId, options.dropMimeTypes, options.dragMimeTypes ?? [], options.hasHandleDrag, this._proxy) : undefined; + ? new TreeViewDragAndDropController(treeViewId, options.dropMimeTypes, options.dragMimeTypes, options.hasHandleDrag, this._proxy) : undefined; const viewer = this.getTreeView(treeViewId); if (viewer) { // Order is important here. The internal tree isn't created until the dataProvider is set. diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 3c02b8b562a..4daf2237cca 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -257,7 +257,7 @@ export interface MainThreadTextEditorsShape extends IDisposable { } export interface MainThreadTreeViewsShape extends IDisposable { - $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[] | undefined; dragMimeTypes: string[] | undefined; hasHandleDrag: boolean }): Promise; + $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean; canSelectMany: boolean; dropMimeTypes: string[]; dragMimeTypes: string[]; hasHandleDrag: boolean }): Promise; $refresh(treeViewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise; $reveal(treeViewId: string, itemInfo: { item: ITreeItem; parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise; $setMessage(treeViewId: string, message: string): void; diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index d473d1b84b4..aef614307af 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -87,8 +87,8 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape { if (!options || !options.treeDataProvider) { throw new Error('Options with treeDataProvider is mandatory'); } - const dropMimeTypes = options.dragAndDropController?.dropMimeTypes; - const dragMimeTypes = options.dragAndDropController?.dragMimeTypes; + const dropMimeTypes = options.dragAndDropController?.dropMimeTypes ?? []; + const dragMimeTypes = options.dragAndDropController?.dragMimeTypes ?? []; const hasHandleDrag = !!options.dragAndDropController?.handleDrag; const registerPromise = this._proxy.$registerTreeViewDataProvider(viewId, { showCollapseAll: !!options.showCollapseAll, canSelectMany: !!options.canSelectMany, dropMimeTypes, dragMimeTypes, hasHandleDrag: hasHandleDrag }); const treeView = this.createExtHostTreeView(viewId, options, extension); @@ -457,7 +457,7 @@ class ExtHostTreeView extends Disposable { if (!target) { return; } - return asPromise(() => this.dndController?.handleDrop(treeDataTransfer, target, token)); + return asPromise(() => this.dndController?.handleDrop(target, treeDataTransfer, token)); } get hasResolve(): boolean { diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index d4d620d61f7..23dd01c2e3e 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -2351,7 +2351,7 @@ export enum TreeItemCollapsibleState { @es5ClassCompat export class TreeDataTransferItem { async asString(): Promise { - return JSON.stringify(this.value); + return typeof this.value === 'string' ? this.value : JSON.stringify(this.value); } constructor(public readonly value: any) { } diff --git a/src/vs/workbench/browser/dnd.ts b/src/vs/workbench/browser/dnd.ts index 7b0dbc38972..d645f38ee5a 100644 --- a/src/vs/workbench/browser/dnd.ts +++ b/src/vs/workbench/browser/dnd.ts @@ -157,12 +157,13 @@ function createDraggedEditorInputFromRawResourcesData(rawResourcesData: string | export async function extractTreeDropData(dataTransfer: ITreeDataTransfer): Promise> { const editors: IDraggedResourceEditorInput[] = []; - const resourcesKey = DataTransfers.RESOURCES.toLowerCase(); + const resourcesKey = Mimes.uriList.toLowerCase(); // Data Transfer: Resources if (dataTransfer.has(resourcesKey)) { try { - const rawResourcesData = await dataTransfer.get(resourcesKey)?.asString(); + const asString = await dataTransfer.get(resourcesKey)?.asString(); + const rawResourcesData = JSON.stringify(asString?.split('\\n').filter(value => !value.startsWith('#'))); editors.push(...createDraggedEditorInputFromRawResourcesData(rawResourcesData)); } catch (error) { // Invalid transfer diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index 9ca06e7d6e1..cd6cd4dc4f1 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -39,7 +39,7 @@ import { isString } from 'vs/base/common/types'; import { ILabelService } from 'vs/platform/label/common/label'; import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list'; import { ITreeRenderer, ITreeNode, IAsyncDataSource, ITreeContextMenuEvent, ITreeDragAndDrop, ITreeDragOverReaction, TreeDragOverBubble } from 'vs/base/browser/ui/tree/tree'; -import { IDragAndDropData } from 'vs/base/browser/dnd'; +import { DataTransfers, IDragAndDropData } from 'vs/base/browser/dnd'; import { FuzzyScore, createMatches } from 'vs/base/common/filters'; import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults'; import { isFalsyOrWhitespace } from 'vs/base/common/strings'; @@ -62,6 +62,7 @@ import { Schemas } from 'vs/base/common/network'; import { ITreeViewsDragAndDropService } from 'vs/workbench/services/views/common/treeViewsDragAndDropService'; import { generateUuid } from 'vs/base/common/uuid'; import { ILogService } from 'vs/platform/log/common/log'; +import { Mimes } from 'vs/base/common/mime'; export class TreeViewPane extends ViewPane { @@ -1266,7 +1267,7 @@ export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop { @IInstantiationService private readonly instantiationService: IInstantiationService, @ITreeViewsDragAndDropService private readonly treeViewsDragAndDropService: ITreeViewsDragAndDropService, @ILogService private readonly logService: ILogService) { - this.treeMimeType = `tree/${treeId.toLowerCase()}`; + this.treeMimeType = `application/vnd.code.tree.${treeId.toLowerCase()}`; } private dndController: ITreeViewDragAndDropController | undefined; @@ -1283,7 +1284,11 @@ export class CustomTreeViewDragAndDrop implements ITreeDragAndDrop { this.dragCancellationToken = new CancellationTokenSource(); this.treeViewsDragAndDropService.addDragOperationTransfer(uuid, this.dndController.handleDrag(itemHandles, uuid, this.dragCancellationToken.token)); originalEvent.dataTransfer.setData(TREE_DRAG_UUID_MIME, uuid); - this.treeItemsTransfer.setData([new DraggedTreeItemsIdentifier(uuid)], DraggedTreeItemsIdentifier.prototype); + if (this.dndController.dragMimeTypes.find((element) => element === Mimes.uriList)) { + this.treeItemsTransfer.setData([new DraggedTreeItemsIdentifier(uuid)], DraggedTreeItemsIdentifier.prototype); + // Add the type that the editor knows + originalEvent.dataTransfer?.setData(DataTransfers.RESOURCES, ''); + } this.dndController.dragMimeTypes.forEach(supportedType => { originalEvent.dataTransfer?.setData(supportedType, ''); }); diff --git a/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts b/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts index 8f243fac548..cf7e685095b 100644 --- a/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts +++ b/src/vscode-dts/vscode.proposed.treeViewDragAndDrop.d.ts @@ -68,7 +68,6 @@ declare module 'vscode' { /** * Provides support for drag and drop in `TreeView`. */ - // todo@API formalize mime types, either `text/uri-list` and or `application/vnd.code.XYZ` (see NotebookOutputItem) export interface TreeDragAndDropController { /** @@ -76,7 +75,7 @@ declare module 'vscode' { * This could be well-defined, existing, mime types, and also mime types defined by the extension. * * Each tree will automatically support drops from it's own `DragAndDropController`. To support drops from other trees, - * you will need to add the mime type of that tree. The mime type of a tree is of the format `tree/treeidlowercase`. + * you will need to add the mime type of that tree. The mime type of a tree is of the format `application/vnd.code.tree.treeidlowercase`. * * To learn the mime type of a dragged item: * 1. Set up your `DragAndDropController` @@ -98,8 +97,8 @@ 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. To specify a cursor position in the file, + * To add a data transfer item that can be dragged into the editor, use the application specific mime type "text/uri-list". + * The data for "text/uri-list" should be a string with `toString()`ed Uris separated by newlines. 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. @@ -115,9 +114,8 @@ declare module 'vscode' { * * @param source The data transfer items of the source of the drag. * @param target The target tree element that the drop is occurring on. - * @param token TODO @alexr00: When would this operation actually be cancelled? + * @param token A cancellation token indicating that the drop has been cancelled. */ - // TODO@API align order of TreeDataTransfer and T with handleDrag - handleDrop(source: TreeDataTransfer, target: T, token: CancellationToken): Thenable | void; + handleDrop(target: T, source: TreeDataTransfer, token: CancellationToken): Thenable | void; } }