Skip to content

Commit

Permalink
Add default uri-list paste providers (#181356)
Browse files Browse the repository at this point in the history
This adds a path and relative path default paste provider when pasting `text/uri-list` types

To do this, I've combined the drop and paste contributions since they are so similar. This lets us easily share the same providers between the two cases
  • Loading branch information
mjbvz committed May 3, 2023
1 parent 09a78d0 commit 9ab88c7
Show file tree
Hide file tree
Showing 12 changed files with 111 additions and 110 deletions.
2 changes: 1 addition & 1 deletion src/vs/editor/common/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1943,7 +1943,7 @@ export enum ExternalUriOpenerPriority {
export interface DocumentOnDropEdit {
readonly label: string;

insertText: string | { snippet: string };
insertText: string | { readonly snippet: string };
additionalEdit?: WorkspaceEdit;
}

Expand Down
45 changes: 0 additions & 45 deletions src/vs/editor/contrib/copyPaste/browser/defaultPasteProviders.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorCommand, EditorContributionInstantiation, ServicesAccessor, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { editorConfigurationBaseNode } from 'vs/editor/common/config/editorConfigurationSchema';
import { CopyPasteController, changePasteTypeCommandId, pasteWidgetVisibleCtx } from 'vs/editor/contrib/copyPaste/browser/copyPasteController';
import { registerEditorFeature } from 'vs/editor/common/editorFeatures';
import { CopyPasteController, changePasteTypeCommandId, pasteWidgetVisibleCtx } from 'vs/editor/contrib/dropOrPasteInto/browser/copyPasteController';
import { DefaultPasteProvidersFeature } from 'vs/editor/contrib/dropOrPasteInto/browser/defaultProviders';
import * as nls from 'vs/nls';
import { ConfigurationScope, Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
Expand Down Expand Up @@ -43,3 +45,5 @@ registerEditorCommand(new class extends EditorCommand {
CopyPasteController.get(editor)?.changePasteType();
}
});

registerEditorFeature(DefaultPasteProvidersFeature);
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ import { Handler, IEditorContribution, PastePayload } from 'vs/editor/common/edi
import { DocumentPasteEdit, DocumentPasteEditProvider } from 'vs/editor/common/languages';
import { ITextModel } from 'vs/editor/common/model';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { registerDefaultPasteProviders } from 'vs/editor/contrib/copyPaste/browser/defaultPasteProviders';
import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';
import { InlineProgressManager } from 'vs/editor/contrib/inlineProgress/browser/inlineProgress';
import { PostEditWidgetManager } from 'vs/editor/contrib/postEditWidget/browser/postEditWidget';
import { PostEditWidgetManager } from './postEditWidget';
import { localize } from 'vs/nls';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
Expand Down Expand Up @@ -81,8 +80,6 @@ export class CopyPasteController extends Disposable implements IEditorContributi
this._pasteProgressManager = this._register(new InlineProgressManager('pasteIntoEditor', editor, instantiationService));

this._postPasteWidgetManager = this._register(instantiationService.createInstance(PostEditWidgetManager, 'pasteIntoEditor', editor, pasteWidgetVisibleCtx, { id: changePasteTypeCommandId, label: localize('postPasteWidgetTitle', "Show paste options...") }));

registerDefaultPasteProviders(_languageFeaturesService);
}

public changePasteType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,46 @@
import { coalesce } from 'vs/base/common/arrays';
import { CancellationToken } from 'vs/base/common/cancellation';
import { UriList, VSDataTransfer } from 'vs/base/common/dataTransfer';
import { Disposable } from 'vs/base/common/lifecycle';
import { Mimes } from 'vs/base/common/mime';
import { Schemas } from 'vs/base/common/network';
import { relativePath } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { IPosition } from 'vs/editor/common/core/position';
import { DocumentOnDropEdit, DocumentOnDropEditProvider } from 'vs/editor/common/languages';
import { IRange } from 'vs/editor/common/core/range';
import { DocumentOnDropEdit, DocumentOnDropEditProvider, DocumentPasteEdit, DocumentPasteEditProvider } 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';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';

class DefaultTextDropProvider implements DocumentOnDropEditProvider {
abstract class SimplePasteAndDropProvider implements DocumentOnDropEditProvider, DocumentPasteEditProvider {

abstract readonly id: string;
abstract readonly dropMimeTypes: readonly string[] | undefined;
abstract readonly pasteMimeTypes: readonly string[];

async provideDocumentPasteEdits(_model: ITextModel, _ranges: readonly IRange[], dataTransfer: VSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined> {
const edit = await this.getEdit(dataTransfer, token);
return edit ? { insertText: edit.insertText, label: edit.label } : undefined;
}

async provideDocumentOnDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<DocumentOnDropEdit | undefined> {
const edit = await this.getEdit(dataTransfer, token);
return edit ? { insertText: edit.insertText, label: edit.label } : undefined;
}

protected abstract getEdit(dataTransfer: VSDataTransfer, token: CancellationToken): Promise<DocumentPasteEdit | undefined>;
}

class DefaultTextProvider extends SimplePasteAndDropProvider {

readonly id = 'text';
readonly dropMimeTypes = [Mimes.text, 'text'];
readonly dropMimeTypes = [Mimes.text];
readonly pasteMimeTypes = [Mimes.text];

async provideDocumentOnDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: VSDataTransfer, _token: CancellationToken): Promise<DocumentOnDropEdit | undefined> {
const textEntry = dataTransfer.get('text') ?? dataTransfer.get(Mimes.text);
protected async getEdit(dataTransfer: VSDataTransfer, _token: CancellationToken) {
const textEntry = dataTransfer.get(Mimes.text);
if (!textEntry) {
return;
}
Expand All @@ -34,20 +56,21 @@ class DefaultTextDropProvider implements DocumentOnDropEditProvider {
return;
}

const text = await textEntry.asString();
const insertText = await textEntry.asString();
return {
label: localize('defaultDropProvider.text.label', "Insert Plain Text"),
insertText: text
label: localize('text.label', "Insert Plain Text"),
insertText
};
}
}

class UriListDropProvider implements DocumentOnDropEditProvider {
class PathProvider extends SimplePasteAndDropProvider {

readonly id = 'uri';
readonly dropMimeTypes = [Mimes.uriList];
readonly pasteMimeTypes = [Mimes.uriList];

async provideDocumentOnDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<DocumentOnDropEdit | undefined> {
protected async getEdit(dataTransfer: VSDataTransfer, token: CancellationToken) {
const entries = await extractUriList(dataTransfer);
if (!entries.length || token.isCancellationRequested) {
return;
Expand Down Expand Up @@ -82,16 +105,19 @@ class UriListDropProvider implements DocumentOnDropEditProvider {
}
}

class RelativePathDropProvider implements DocumentOnDropEditProvider {
class RelativePathProvider extends SimplePasteAndDropProvider {

readonly id = 'relativePath';
readonly dropMimeTypes = [Mimes.uriList];
readonly pasteMimeTypes = [Mimes.uriList];

constructor(
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService
) { }
) {
super();
}

async provideDocumentOnDropEdits(_model: ITextModel, _position: IPosition, dataTransfer: VSDataTransfer, token: CancellationToken): Promise<DocumentOnDropEdit | undefined> {
protected async getEdit(dataTransfer: VSDataTransfer, token: CancellationToken) {
const entries = await extractUriList(dataTransfer);
if (!entries.length || token.isCancellationRequested) {
return;
Expand Down Expand Up @@ -133,18 +159,28 @@ async function extractUriList(dataTransfer: VSDataTransfer): Promise<{ readonly
return entries;
}

export class DefaultDropProvidersFeature extends Disposable {
constructor(
@ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService,
@IWorkspaceContextService workspaceContextService: IWorkspaceContextService,
) {
super();

this._register(languageFeaturesService.documentOnDropEditProvider.register('*', new DefaultTextProvider()));
this._register(languageFeaturesService.documentOnDropEditProvider.register('*', new PathProvider()));
this._register(languageFeaturesService.documentOnDropEditProvider.register('*', new RelativePathProvider(workspaceContextService)));
}
}

let registeredDefaultProviders = false;

export function registerDefaultDropProviders(
languageFeaturesService: ILanguageFeaturesService,
workspaceContextService: IWorkspaceContextService,
) {
if (!registeredDefaultProviders) {
registeredDefaultProviders = true;

languageFeaturesService.documentOnDropEditProvider.register('*', new DefaultTextDropProvider());
languageFeaturesService.documentOnDropEditProvider.register('*', new UriListDropProvider());
languageFeaturesService.documentOnDropEditProvider.register('*', new RelativePathDropProvider(workspaceContextService));
export class DefaultPasteProvidersFeature extends Disposable {
constructor(
@ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService,
@IWorkspaceContextService workspaceContextService: IWorkspaceContextService,
) {
super();

this._register(languageFeaturesService.documentPasteEditProvider.register('*', new DefaultTextProvider()));
this._register(languageFeaturesService.documentPasteEditProvider.register('*', new PathProvider()));
this._register(languageFeaturesService.documentPasteEditProvider.register('*', new RelativePathProvider(workspaceContextService)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorCommand, EditorContributionInstantiation, ServicesAccessor, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { registerEditorFeature } from 'vs/editor/common/editorFeatures';
import { DefaultDropProvidersFeature } from 'vs/editor/contrib/dropOrPasteInto/browser/defaultProviders';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { DropIntoEditorController, changeDropTypeCommandId, dropWidgetVisibleCtx } from './dropIntoEditorController';


registerEditorContribution(DropIntoEditorController.ID, DropIntoEditorController, EditorContributionInstantiation.BeforeFirstInteraction);

registerEditorCommand(new class extends EditorCommand {
constructor() {
super({
id: changeDropTypeCommandId,
precondition: dropWidgetVisibleCtx,
kbOpts: {
weight: KeybindingWeight.EditorContrib,
primary: KeyMod.CtrlCmd | KeyCode.Period,
}
});
}

public override runEditorCommand(_accessor: ServicesAccessor | null, editor: ICodeEditor, _args: any) {
DropIntoEditorController.get(editor)?.changeDropType();
}
});

registerEditorFeature(DefaultDropProvidersFeature);
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@
import { coalesce } from 'vs/base/common/arrays';
import { CancelablePromise, createCancelablePromise, raceCancellation } from 'vs/base/common/async';
import { VSDataTransfer } from 'vs/base/common/dataTransfer';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { Disposable } from 'vs/base/common/lifecycle';
import { addExternalEditorsDropData, toVSDataTransfer } from 'vs/editor/browser/dnd';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorCommand, EditorContributionInstantiation, ServicesAccessor, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { IPosition } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
Expand All @@ -19,18 +17,16 @@ import { DraggedTreeItemsIdentifier } from 'vs/editor/common/services/treeViewsD
import { ITreeViewsDnDService } from 'vs/editor/common/services/treeViewsDndService';
import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';
import { InlineProgressManager } from 'vs/editor/contrib/inlineProgress/browser/inlineProgress';
import { PostEditWidgetManager } from 'vs/editor/contrib/postEditWidget/browser/postEditWidget';
import { localize } from 'vs/nls';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { LocalSelectionTransfer } from 'vs/platform/dnd/browser/dnd';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { registerDefaultDropProviders } from './defaultOnDropProviders';
import { PostEditWidgetManager } from './postEditWidget';

const changeDropTypeCommandId = 'editor.changeDropType';
export const changeDropTypeCommandId = 'editor.changeDropType';

const dropWidgetVisibleCtx = new RawContextKey<boolean>('dropWidgetVisible', false, localize('dropWidgetVisible', "Whether the drop widget is showing"));
export const dropWidgetVisibleCtx = new RawContextKey<boolean>('dropWidgetVisible', false, localize('dropWidgetVisible', "Whether the drop widget is showing"));

export class DropIntoEditorController extends Disposable implements IEditorContribution {

Expand All @@ -52,16 +48,14 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
@IInstantiationService instantiationService: IInstantiationService,
@IWorkspaceContextService workspaceContextService: IWorkspaceContextService,
@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,
@ITreeViewsDnDService private readonly _treeViewsDragAndDropService: ITreeViewsDnDService,
@ITreeViewsDnDService private readonly _treeViewsDragAndDropService: ITreeViewsDnDService
) {
super();

this._dropProgressManager = this._register(instantiationService.createInstance(InlineProgressManager, 'dropIntoEditor', editor));
this._postDropWidgetManager = this._register(instantiationService.createInstance(PostEditWidgetManager, 'dropIntoEditor', editor, dropWidgetVisibleCtx, { id: changeDropTypeCommandId, label: localize('postDropWidgetTitle', "Show drop options...") }));

this._register(editor.onDropIntoEditor(e => this.onDropIntoEditor(editor, e.position, e.event)));

registerDefaultDropProviders(this._languageFeaturesService, workspaceContextService);
}

public clearWidgets() {
Expand Down Expand Up @@ -155,22 +149,3 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
return dataTransfer;
}
}

registerEditorContribution(DropIntoEditorController.ID, DropIntoEditorController, EditorContributionInstantiation.BeforeFirstInteraction);

registerEditorCommand(new class extends EditorCommand {
constructor() {
super({
id: changeDropTypeCommandId,
precondition: dropWidgetVisibleCtx,
kbOpts: {
weight: KeybindingWeight.EditorContrib,
primary: KeyMod.CtrlCmd | KeyCode.Period,
}
});
}

public override runEditorCommand(_accessor: ServicesAccessor | null, editor: ICodeEditor, _args: any) {
DropIntoEditorController.get(editor)?.changeDropType();
}
});
4 changes: 2 additions & 2 deletions src/vs/editor/editor.all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import 'vs/editor/contrib/codeAction/browser/codeActionContributions';
import 'vs/editor/contrib/codelens/browser/codelensController';
import 'vs/editor/contrib/colorPicker/browser/colorContributions';
import 'vs/editor/contrib/colorPicker/browser/standaloneColorPickerActions';
import 'vs/editor/contrib/copyPaste/browser/copyPasteContribution';
import 'vs/editor/contrib/comment/browser/comment';
import 'vs/editor/contrib/contextmenu/browser/contextmenu';
import 'vs/editor/contrib/cursorUndo/browser/cursorUndo';
import 'vs/editor/contrib/dnd/browser/dnd';
import 'vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution';
import 'vs/editor/contrib/dropOrPasteInto/browser/copyPasteContribution';
import 'vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorContribution';
import 'vs/editor/contrib/find/browser/findController';
import 'vs/editor/contrib/folding/browser/folding';
import 'vs/editor/contrib/fontZoom/browser/fontZoom';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ import { IDimension } from 'vs/editor/common/core/dimension';
import { CellFindMatchModel } from 'vs/workbench/contrib/notebook/browser/contrib/find/findModel';
import { INotebookLoggingService } from 'vs/workbench/contrib/notebook/common/notebookLoggingService';
import { Schemas } from 'vs/base/common/network';
import { DropIntoEditorController } from 'vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution';
import { CopyPasteController } from 'vs/editor/contrib/copyPaste/browser/copyPasteController';
import { DropIntoEditorController } from 'vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorController';
import { CopyPasteController } from 'vs/editor/contrib/dropOrPasteInto/browser/copyPasteController';

const $ = DOM.$;

Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/contrib/scm/browser/scmViewPane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ import { Button, ButtonWithDescription, ButtonWithDropdown } from 'vs/base/brows
import { INotificationService } from 'vs/platform/notification/common/notification';
import { RepositoryContextKeys } from 'vs/workbench/contrib/scm/browser/scmViewService';
import { DragAndDropController } from 'vs/editor/contrib/dnd/browser/dnd';
import { DropIntoEditorController } from 'vs/editor/contrib/dropIntoEditor/browser/dropIntoEditorContribution';
import { DropIntoEditorController } from 'vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorController';
import { MessageController } from 'vs/editor/contrib/message/browser/messageController';
import { contrastBorder, registerColor } from 'vs/platform/theme/common/colorRegistry';
import { defaultButtonStyles, defaultCountBadgeStyles } from 'vs/platform/theme/browser/defaultStyles';
Expand Down

0 comments on commit 9ab88c7

Please sign in to comment.