Remove terminal knowledge from dnd component

Fixes #129954
This commit is contained in:
Daniel Imms 2022-03-29 06:00:36 -07:00
parent b8ea8c0d33
commit a57c64f9c0
9 changed files with 113 additions and 42 deletions

View file

@ -71,12 +71,7 @@ export const DataTransfers = {
/**
* Typically transfer type for copy/paste transfers.
*/
TEXT: Mimes.text,
/**
* Application specific terminal transfer type.
*/
TERMINALS: 'Terminals'
TEXT: Mimes.text
};
export function applyDragImage(event: DragEvent, label: string | null, clazz: string): void {

View file

@ -41,6 +41,7 @@ import { ITreeDragOverReaction } from 'vs/base/browser/ui/tree/tree';
import { WebFileSystemAccess } from 'vs/platform/files/browser/webFileSystemAccess';
import { HTMLFileSystemProvider } from 'vs/platform/files/browser/htmlFileSystemProvider';
import { DeferredPromise } from 'vs/base/common/async';
import { Registry } from 'vs/platform/registry/common/platform';
//#region Editor / Resources DND
@ -132,19 +133,6 @@ export async function extractEditorsDropData(accessor: ServicesAccessor, e: Drag
}
}
// Check for terminals transfer
const terminals = e.dataTransfer.getData(DataTransfers.TERMINALS);
if (terminals) {
try {
const terminalEditors: string[] = JSON.parse(terminals);
for (const terminalEditor of terminalEditors) {
editors.push({ resource: URI.parse(terminalEditor) });
}
} catch (error) {
// Invalid transfer
}
}
// Web: Check for file transfer
if (isWeb && containsDragType(e, DataTransfers.FILES)) {
const files = e.dataTransfer.items;
@ -156,6 +144,19 @@ export async function extractEditorsDropData(accessor: ServicesAccessor, e: Drag
}
}
}
// Workbench contributions
const contributions = Registry.as<IDragAndDropContributionRegistry>(Extensions.DragAndDropContribution).getAll();
for (const contribution of contributions) {
const data = e.dataTransfer.getData(contribution.dataFormatKey);
if (data) {
try {
editors.push(...contribution.getEditorInputs(data));
} catch (error) {
// Invalid transfer
}
}
}
}
return editors;
@ -502,10 +503,10 @@ export function fillEditorsDragData(accessor: ServicesAccessor, resourcesOrEdito
event.dataTransfer.setData(DataTransfers.RESOURCES, JSON.stringify(files.map(({ resource }) => resource.toString())));
}
// Terminal URI
const terminalResources = resources.filter(({ resource }) => resource.scheme === Schemas.vscodeTerminal);
if (terminalResources.length) {
event.dataTransfer.setData(DataTransfers.TERMINALS, JSON.stringify(terminalResources.map(({ resource }) => resource.toString())));
// Contributions
const contributions = Registry.as<IDragAndDropContributionRegistry>(Extensions.DragAndDropContribution).getAll();
for (const contribution of contributions) {
contribution.setData(resources, event);
}
// Editors: enables cross window DND of editors
@ -590,6 +591,49 @@ export function fillEditorsDragData(accessor: ServicesAccessor, resourcesOrEdito
//#endregion
//#region DND contributions
export interface IDragAndDropContributionRegistry {
/**
* Registers a drag and drop contribution.
*/
register(contribution: IDragAndDropContribution): void;
/**
* Returns all registered drag and drop contributions.
*/
getAll(): IterableIterator<IDragAndDropContribution>;
}
export interface IDragAndDropContribution {
readonly dataFormatKey: string;
getEditorInputs(data: string): IDraggedResourceEditorInput[];
setData(resources: IResourceStat[], event: DragMouseEvent | DragEvent): void;
}
class DragAndDropContributionRegistry implements IDragAndDropContributionRegistry {
private readonly _contributions = new Map<string, IDragAndDropContribution>();
register(contribution: IDragAndDropContribution): void {
if (this._contributions.has(contribution.dataFormatKey)) {
throw new Error(`A drag and drop contributiont with key '${contribution.dataFormatKey}' was already registered.`);
}
this._contributions.set(contribution.dataFormatKey, contribution);
}
getAll(): IterableIterator<IDragAndDropContribution> {
return this._contributions.values();
}
}
export const Extensions = {
DragAndDropContribution: 'base.contributions.dragAndDrop'
};
Registry.add(Extensions.DragAndDropContribution, new DragAndDropContributionRegistry());
//#endregion
//#region DND Utilities
/**

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/editordroptarget';
import { LocalSelectionTransfer, DraggedEditorIdentifier, ResourcesDropHandler, DraggedEditorGroupIdentifier, containsDragType, CodeDataTransfers, DraggedTreeItemsIdentifier, extractTreeDropData } from 'vs/workbench/browser/dnd';
import { Extensions as DragAndDropExtensions, LocalSelectionTransfer, DraggedEditorIdentifier, ResourcesDropHandler, DraggedEditorGroupIdentifier, containsDragType, CodeDataTransfers, DraggedTreeItemsIdentifier, extractTreeDropData, IDragAndDropContributionRegistry } from 'vs/workbench/browser/dnd';
import { addDisposableListener, EventType, EventHelper, isAncestor, DragAndDropObserver } 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';
@ -22,6 +22,7 @@ import { assertIsDefined, assertAllDefined } from 'vs/base/common/types';
import { ITreeViewsService } from 'vs/workbench/services/views/browser/treeViewsService';
import { isTemporaryWorkspace, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { Registry } from 'vs/platform/registry/common/platform';
interface IDropOperation {
splitDirection?: GroupDirection;
@ -575,10 +576,14 @@ export class EditorDropTarget extends Themable {
if (
!this.editorTransfer.hasData(DraggedEditorIdentifier.prototype) &&
!this.groupTransfer.hasData(DraggedEditorGroupIdentifier.prototype) &&
event.dataTransfer && !containsDragType(event, DataTransfers.FILES, CodeDataTransfers.FILES, DataTransfers.RESOURCES, DataTransfers.TERMINALS, CodeDataTransfers.EDITORS) // see https://github.com/microsoft/vscode/issues/25789
event.dataTransfer
) {
event.dataTransfer.dropEffect = 'none';
return; // unsupported transfer
const dndContributions = Registry.as<IDragAndDropContributionRegistry>(DragAndDropExtensions.DragAndDropContribution).getAll();
const dndContributionKeys = Array.from(dndContributions).map(e => e.dataFormatKey);
if (!containsDragType(event, DataTransfers.FILES, CodeDataTransfers.FILES, DataTransfers.RESOURCES, CodeDataTransfers.EDITORS, ...dndContributionKeys)) { // see https://github.com/microsoft/vscode/issues/25789
event.dataTransfer.dropEffect = 'none';
return; // unsupported transfer
}
}
// Signal DND start

View file

@ -9,12 +9,14 @@ import 'vs/css!./media/terminal';
import 'vs/css!./media/widgets';
import 'vs/css!./media/xterm';
import * as nls from 'vs/nls';
import { URI } from 'vs/base/common/uri';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
import { KeybindingWeight, KeybindingsRegistry, IKeybindings } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { getQuickNavigateHandler } from 'vs/workbench/browser/quickaccess';
import { Extensions as ViewContainerExtensions, IViewContainersRegistry, ViewContainerLocation, IViewsRegistry } from 'vs/workbench/common/views';
import { Extensions as DragAndDropExtensions, IDragAndDropContributionRegistry, IDraggedResourceEditorInput } from 'vs/workbench/browser/dnd';
import { registerTerminalActions, terminalSendSequenceCommand } from 'vs/workbench/contrib/terminal/browser/terminalActions';
import { TerminalViewPane } from 'vs/workbench/contrib/terminal/browser/terminalView';
import { TERMINAL_VIEW_ID, TerminalCommandId, ITerminalProfileService } from 'vs/workbench/contrib/terminal/common/terminal';
@ -22,7 +24,7 @@ import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalCol
import { setupTerminalCommands } from 'vs/workbench/contrib/terminal/browser/terminalCommands';
import { TerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ITerminalEditorService, ITerminalGroupService, ITerminalInstanceService, ITerminalService, terminalEditorId } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalEditorService, ITerminalGroupService, ITerminalInstanceService, ITerminalService, TerminalDataTransfers, terminalEditorId } from 'vs/workbench/contrib/terminal/browser/terminal';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from 'vs/platform/quickinput/common/quickAccess';
@ -49,6 +51,7 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } fr
import { RemoteTerminalBackendContribution } from 'vs/workbench/contrib/terminal/browser/remoteTerminalBackend';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { TerminalMainContribution } from 'vs/workbench/contrib/terminal/browser/terminalMainContribution';
import { Schemas } from 'vs/base/common/network';
// Register services
registerSingleton(ITerminalService, TerminalService, true);
@ -81,6 +84,7 @@ workbenchRegistry.registerWorkbenchContribution(RemoteTerminalBackendContributio
registerTerminalPlatformConfiguration();
registerTerminalConfiguration();
// Register editor/dnd contributions
Registry.as<IEditorFactoryRegistry>(EditorExtensions.EditorFactory).registerEditorSerializer(TerminalEditorInput.ID, TerminalInputSerializer);
Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane(
EditorPaneDescriptor.create(
@ -92,6 +96,27 @@ Registry.as<IEditorPaneRegistry>(EditorExtensions.EditorPane).registerEditorPane
new SyncDescriptor(TerminalEditorInput)
]
);
Registry.as<IDragAndDropContributionRegistry>(DragAndDropExtensions.DragAndDropContribution).register({
dataFormatKey: TerminalDataTransfers.Terminals,
getEditorInputs(data) {
const editors: IDraggedResourceEditorInput[] = [];
try {
const terminalEditors: string[] = JSON.parse(data);
for (const terminalEditor of terminalEditors) {
editors.push({ resource: URI.parse(terminalEditor) });
}
} catch (error) {
// Invalid transfer
}
return editors;
},
setData(resources, event) {
const terminalResources = resources.filter(({ resource }) => resource.scheme === Schemas.vscodeTerminal);
if (terminalResources.length) {
event.dataTransfer?.setData(TerminalDataTransfers.Terminals, JSON.stringify(terminalResources.map(({ resource }) => resource.toString())));
}
}
});
// Register views
const VIEW_CONTAINER = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({

View file

@ -918,3 +918,7 @@ export const enum LinuxDistro {
Fedora = 2,
Ubuntu = 3,
}
export const enum TerminalDataTransfers {
Terminals = 'Terminals'
}

View file

@ -52,7 +52,7 @@ import { CodeDataTransfers, containsDragType } from 'vs/workbench/browser/dnd';
import { IViewDescriptorService, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views';
import { IDetectedLinks, TerminalLinkManager } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkManager';
import { TerminalLinkQuickpick } from 'vs/workbench/contrib/terminal/browser/links/terminalLinkQuickpick';
import { IRequestAddInstanceToGroupEvent, ITerminalExternalLinkProvider, ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { IRequestAddInstanceToGroupEvent, ITerminalExternalLinkProvider, ITerminalInstance, TerminalDataTransfers } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalLaunchHelpAction } from 'vs/workbench/contrib/terminal/browser/terminalActions';
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput';
@ -2282,7 +2282,7 @@ class TerminalInstanceDragAndDropController extends Disposable implements dom.ID
}
onDragEnter(e: DragEvent) {
if (!containsDragType(e, DataTransfers.FILES, DataTransfers.RESOURCES, DataTransfers.TERMINALS, CodeDataTransfers.FILES)) {
if (!containsDragType(e, DataTransfers.FILES, DataTransfers.RESOURCES, TerminalDataTransfers.Terminals, CodeDataTransfers.FILES)) {
return;
}
@ -2292,7 +2292,7 @@ class TerminalInstanceDragAndDropController extends Disposable implements dom.ID
}
// Dragging terminals
if (containsDragType(e, DataTransfers.TERMINALS)) {
if (containsDragType(e, TerminalDataTransfers.Terminals)) {
const side = this._getDropSide(e);
this._dropOverlay.classList.toggle('drop-before', side === 'before');
this._dropOverlay.classList.toggle('drop-after', side === 'after');
@ -2316,7 +2316,7 @@ class TerminalInstanceDragAndDropController extends Disposable implements dom.ID
}
// Dragging terminals
if (containsDragType(e, DataTransfers.TERMINALS)) {
if (containsDragType(e, TerminalDataTransfers.Terminals)) {
const side = this._getDropSide(e);
this._dropOverlay.classList.toggle('drop-before', side === 'before');
this._dropOverlay.classList.toggle('drop-after', side === 'after');

View file

@ -9,7 +9,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IThemeService, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { ITerminalGroupService, ITerminalInstance, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalGroupService, ITerminalInstance, ITerminalService, TerminalDataTransfers } from 'vs/workbench/contrib/terminal/browser/terminal';
import { localize } from 'vs/nls';
import * as DOM from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@ -585,13 +585,13 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop<ITerminalInstance> {
// Attach terminals type to event
const terminals: ITerminalInstance[] = dndData.filter(e => 'instanceId' in (e as any));
if (terminals.length > 0) {
originalEvent.dataTransfer.setData(DataTransfers.TERMINALS, JSON.stringify(terminals.map(e => e.resource.toString())));
originalEvent.dataTransfer.setData(TerminalDataTransfers.Terminals, JSON.stringify(terminals.map(e => e.resource.toString())));
}
}
onDragOver(data: IDragAndDropData, targetInstance: ITerminalInstance | undefined, targetIndex: number | undefined, originalEvent: DragEvent): boolean | IListDragOverReaction {
if (data instanceof NativeDragAndDropData) {
if (!containsDragType(originalEvent, DataTransfers.FILES, DataTransfers.RESOURCES, DataTransfers.TERMINALS, CodeDataTransfers.FILES)) {
if (!containsDragType(originalEvent, DataTransfers.FILES, DataTransfers.RESOURCES, TerminalDataTransfers.Terminals, CodeDataTransfers.FILES)) {
return false;
}
}
@ -602,7 +602,7 @@ class TerminalTabsDragAndDrop implements IListDragAndDrop<ITerminalInstance> {
this._autoFocusInstance = targetInstance;
}
if (!targetInstance && !containsDragType(originalEvent, DataTransfers.TERMINALS)) {
if (!targetInstance && !containsDragType(originalEvent, TerminalDataTransfers.Terminals)) {
return data instanceof ElementsDragAndDropData;
}

View file

@ -3,10 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DataTransfers } from 'vs/base/browser/dnd';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ITerminalInstance, TerminalDataTransfers } from 'vs/workbench/contrib/terminal/browser/terminal';
export function parseTerminalUri(resource: URI): ITerminalIdentifier {
const [, workspaceId, instanceId] = resource.path.split('/');
@ -34,7 +33,7 @@ export interface IPartialDragEvent {
}
export function getTerminalResourcesFromDragEvent(event: IPartialDragEvent): URI[] | undefined {
const resources = event.dataTransfer?.getData(DataTransfers.TERMINALS);
const resources = event.dataTransfer?.getData(TerminalDataTransfers.Terminals);
if (resources) {
const json = JSON.parse(resources);
const result = [];

View file

@ -14,7 +14,7 @@ import { IThemeService, IColorTheme, registerThemingParticipant, ICssStyleCollec
import { switchTerminalActionViewItemSeparator, switchTerminalShowTabsTitle } from 'vs/workbench/contrib/terminal/browser/terminalActions';
import { TERMINAL_BACKGROUND_COLOR, TERMINAL_BORDER_COLOR, TERMINAL_DRAG_AND_DROP_BACKGROUND, TERMINAL_TAB_ACTIVE_BORDER } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification';
import { ICreateTerminalOptions, ITerminalGroupService, ITerminalInstance, ITerminalService, TerminalConnectionState } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ICreateTerminalOptions, ITerminalGroupService, ITerminalInstance, ITerminalService, TerminalConnectionState, TerminalDataTransfers } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
@ -42,7 +42,6 @@ import { ColorScheme } from 'vs/platform/theme/common/theme';
import { getColorClass, getUriClasses } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
import { terminalStrings } from 'vs/workbench/contrib/terminal/common/terminalStrings';
import { withNullAsUndefined } from 'vs/base/common/types';
import { DataTransfers } from 'vs/base/browser/dnd';
import { getTerminalActionBarArgs } from 'vs/workbench/contrib/terminal/browser/terminalMenus';
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
import { getShellIntegrationTooltip } from 'vs/workbench/contrib/terminal/browser/terminalTooltip';
@ -449,7 +448,7 @@ class SingleTerminalTabActionViewItem extends MenuEntryActionViewItem {
this._elementDisposables.push(dom.addDisposableListener(this.element, dom.EventType.DRAG_START, e => {
const instance = this._terminalGroupService.activeInstance;
if (e.dataTransfer && instance) {
e.dataTransfer.setData(DataTransfers.TERMINALS, JSON.stringify([instance.resource.toString()]));
e.dataTransfer.setData(TerminalDataTransfers.Terminals, JSON.stringify([instance.resource.toString()]));
}
}));
}