Add setting to disable paste as functionality and paste widget (#181375)

For #30066

This removes the `editor.experimental.pasteActions.enabled` setting in favor of `editor.pasteAs.enabled` (which also defaults to on)
This commit is contained in:
Matt Bierner 2023-05-02 23:55:06 -07:00 committed by GitHub
parent d72fdc29d2
commit 6384b9bcdf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 233 additions and 156 deletions

View file

@ -36,8 +36,8 @@
"configuration.markdown.suggest.paths.includeWorkspaceHeaderCompletions.never": "Disable workspace header suggestions.",
"configuration.markdown.suggest.paths.includeWorkspaceHeaderCompletions.onDoubleHash": "Enable workspace header suggestions after typing `##` in a path, for example `[link text](##`.",
"configuration.markdown.suggest.paths.includeWorkspaceHeaderCompletions.onSingleOrDoubleHash": "Enable workspace header suggestions after typing either `##` or `#` in a path, for example `[link text](#` or `[link text](##`.",
"configuration.markdown.editor.drop.enabled": "Enable dropping files into a Markdown editor while holding Shift. Requires enabling `#editor.dropIntoEditor.enabled#`.",
"configuration.markdown.editor.pasteLinks.enabled": "Enable pasting files into a Markdown editor inserts Markdown links. Requires enabling `#editor.experimental.pasteActions.enabled#`.",
"configuration.markdown.editor.drop.enabled": "Enable dropping files into a Markdown editor while holding Shift. Requires enabling `#editor.pasteAs.enabled#`.",
"configuration.markdown.editor.pasteLinks.enabled": "Enable pasting files into a Markdown editor inserts Markdown links. Requires enabling `#editor.pasteAs.enabled#`.",
"configuration.markdown.validate.enabled.description": "Enable all error reporting in Markdown files.",
"configuration.markdown.validate.referenceLinks.enabled.description": "Validate reference links in Markdown files, for example `[link][ref]`. Requires enabling `#markdown.validate.enabled#`.",
"configuration.markdown.validate.fragmentLinks.enabled.description": "Validate fragment links to headers in the current Markdown file, for example `[link](#header)`. Requires enabling `#markdown.validate.enabled#`.",

View file

@ -707,6 +707,11 @@ export interface IEditorOptions {
*/
dropIntoEditor?: IDropIntoEditorOptions;
/**
* Controls support for changing how content is pasted into the editor.
*/
pasteAs?: IPasteAsOptions;
/**
* Controls whether the editor receives tabs or defers them to the workbench for navigation.
*/
@ -4794,6 +4799,73 @@ class EditorDropIntoEditor extends BaseEditorOption<EditorOption.dropIntoEditor,
//#endregion
//#region pasteAs
/**
* Configuration options for editor pasting as into behavior
*/
export interface IPasteAsOptions {
/**
* Enable paste as functionality in editors.
* Defaults to true.
*/
enabled?: boolean;
/**
* Controls if a widget is shown after a drop.
* Defaults to 'afterPaste'.
*/
showPasteSelector?: 'afterPaste' | 'never';
}
/**
* @internal
*/
export type EditorPasteAsOptions = Readonly<Required<IPasteAsOptions>>;
class EditorPasteAs extends BaseEditorOption<EditorOption.pasteAs, IPasteAsOptions, EditorPasteAsOptions> {
constructor() {
const defaults: EditorPasteAsOptions = { enabled: true, showPasteSelector: 'afterPaste' };
super(
EditorOption.pasteAs, 'pasteAs', defaults,
{
'editor.PasteAs.enabled': {
type: 'boolean',
default: defaults.enabled,
markdownDescription: nls.localize('pasteAs.enabled', "Controls whether you can paste content in different ways."),
},
'editor.PasteAs.showPasteSelector': {
type: 'string',
markdownDescription: nls.localize('pasteAs.showPasteSelector', "Controls if a widget is shown when pasting content in to the editor. This widget lets you control how the file is pasted."),
enum: [
'afterPaste',
'never'
],
enumDescriptions: [
nls.localize('pasteAs.showPasteSelector.afterPaste', "Show the paste selector widget after content is pasted into the editor."),
nls.localize('pasteAs.showPasteSelector.never', "Never show the paste selector widget. Instead the default pasting behavior is always used."),
],
default: 'afterPaste',
},
}
);
}
public validate(_input: any): EditorPasteAsOptions {
if (!_input || typeof _input !== 'object') {
return this.defaultValue;
}
const input = _input as IPasteAsOptions;
return {
enabled: boolean(input.enabled, this.defaultValue.enabled),
showPasteSelector: stringSet(input.showPasteSelector, this.defaultValue.showPasteSelector, ['afterPaste', 'never']),
};
}
}
//#endregion
const DEFAULT_WINDOWS_FONT_FAMILY = 'Consolas, \'Courier New\', monospace';
const DEFAULT_MAC_FONT_FAMILY = 'Menlo, Monaco, \'Courier New\', monospace';
const DEFAULT_LINUX_FONT_FAMILY = '\'Droid Sans Mono\', \'monospace\', monospace';
@ -4906,6 +4978,7 @@ export const enum EditorOption {
overviewRulerBorder,
overviewRulerLanes,
padding,
pasteAs,
parameterHints,
peekWidgetDefaultFocus,
definitionLinkOpensInPeek,
@ -5382,6 +5455,7 @@ export const EditorOptions = {
3, 0, 3
)),
padding: register(new EditorPadding()),
pasteAs: register(new EditorPasteAs()),
parameterHints: register(new EditorParameterHints()),
peekWidgetDefaultFocus: register(new EditorStringEnumOption(
EditorOption.peekWidgetDefaultFocus, 'peekWidgetDefaultFocus',

View file

@ -255,66 +255,67 @@ export enum EditorOption {
overviewRulerBorder = 79,
overviewRulerLanes = 80,
padding = 81,
parameterHints = 82,
peekWidgetDefaultFocus = 83,
definitionLinkOpensInPeek = 84,
quickSuggestions = 85,
quickSuggestionsDelay = 86,
readOnly = 87,
renameOnType = 88,
renderControlCharacters = 89,
renderFinalNewline = 90,
renderLineHighlight = 91,
renderLineHighlightOnlyWhenFocus = 92,
renderValidationDecorations = 93,
renderWhitespace = 94,
revealHorizontalRightPadding = 95,
roundedSelection = 96,
rulers = 97,
scrollbar = 98,
scrollBeyondLastColumn = 99,
scrollBeyondLastLine = 100,
scrollPredominantAxis = 101,
selectionClipboard = 102,
selectionHighlight = 103,
selectOnLineNumbers = 104,
showFoldingControls = 105,
showUnused = 106,
snippetSuggestions = 107,
smartSelect = 108,
smoothScrolling = 109,
stickyScroll = 110,
stickyTabStops = 111,
stopRenderingLineAfter = 112,
suggest = 113,
suggestFontSize = 114,
suggestLineHeight = 115,
suggestOnTriggerCharacters = 116,
suggestSelection = 117,
tabCompletion = 118,
tabIndex = 119,
unicodeHighlighting = 120,
unusualLineTerminators = 121,
useShadowDOM = 122,
useTabStops = 123,
wordBreak = 124,
wordSeparators = 125,
wordWrap = 126,
wordWrapBreakAfterCharacters = 127,
wordWrapBreakBeforeCharacters = 128,
wordWrapColumn = 129,
wordWrapOverride1 = 130,
wordWrapOverride2 = 131,
wrappingIndent = 132,
wrappingStrategy = 133,
showDeprecated = 134,
inlayHints = 135,
editorClassName = 136,
pixelRatio = 137,
tabFocusMode = 138,
layoutInfo = 139,
wrappingInfo = 140,
defaultColorDecorators = 141
pasteAs = 82,
parameterHints = 83,
peekWidgetDefaultFocus = 84,
definitionLinkOpensInPeek = 85,
quickSuggestions = 86,
quickSuggestionsDelay = 87,
readOnly = 88,
renameOnType = 89,
renderControlCharacters = 90,
renderFinalNewline = 91,
renderLineHighlight = 92,
renderLineHighlightOnlyWhenFocus = 93,
renderValidationDecorations = 94,
renderWhitespace = 95,
revealHorizontalRightPadding = 96,
roundedSelection = 97,
rulers = 98,
scrollbar = 99,
scrollBeyondLastColumn = 100,
scrollBeyondLastLine = 101,
scrollPredominantAxis = 102,
selectionClipboard = 103,
selectionHighlight = 104,
selectOnLineNumbers = 105,
showFoldingControls = 106,
showUnused = 107,
snippetSuggestions = 108,
smartSelect = 109,
smoothScrolling = 110,
stickyScroll = 111,
stickyTabStops = 112,
stopRenderingLineAfter = 113,
suggest = 114,
suggestFontSize = 115,
suggestLineHeight = 116,
suggestOnTriggerCharacters = 117,
suggestSelection = 118,
tabCompletion = 119,
tabIndex = 120,
unicodeHighlighting = 121,
unusualLineTerminators = 122,
useShadowDOM = 123,
useTabStops = 124,
wordBreak = 125,
wordSeparators = 126,
wordWrap = 127,
wordWrapBreakAfterCharacters = 128,
wordWrapBreakBeforeCharacters = 129,
wordWrapColumn = 130,
wordWrapOverride1 = 131,
wordWrapOverride2 = 132,
wrappingIndent = 133,
wrappingStrategy = 134,
showDeprecated = 135,
inlayHints = 136,
editorClassName = 137,
pixelRatio = 138,
tabFocusMode = 139,
layoutInfo = 140,
wrappingInfo = 141,
defaultColorDecorators = 142
}
/**

View file

@ -6,29 +6,13 @@
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 { 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';
import { Registry } from 'vs/platform/registry/common/platform';
registerEditorContribution(CopyPasteController.ID, CopyPasteController, EditorContributionInstantiation.Eager); // eager because it listens to events on the container dom node of the editor
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
...editorConfigurationBaseNode,
properties: {
'editor.experimental.pasteActions.enabled': {
type: 'boolean',
scope: ConfigurationScope.LANGUAGE_OVERRIDABLE,
description: nls.localize('pasteActions', "Enable/disable running edits from extensions on paste."),
default: false,
},
}
});
registerEditorCommand(new class extends EditorCommand {
constructor() {
super({

View file

@ -10,7 +10,6 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { UriList, VSDataTransfer, createStringDataTransferItem } 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 { generateUuid } from 'vs/base/common/uuid';
import { toVSDataTransfer } from 'vs/editor/browser/dnd';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
@ -23,12 +22,11 @@ import { ITextModel } from 'vs/editor/common/model';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';
import { InlineProgressManager } from 'vs/editor/contrib/inlineProgress/browser/inlineProgress';
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';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { PostEditWidgetManager } from './postEditWidget';
export const changePasteTypeCommandId = 'editor.changePasteType';
@ -65,7 +63,6 @@ export class CopyPasteController extends Disposable implements IEditorContributi
editor: ICodeEditor,
@IInstantiationService instantiationService: IInstantiationService,
@IClipboardService private readonly _clipboardService: IClipboardService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,
) {
super();
@ -90,13 +87,8 @@ export class CopyPasteController extends Disposable implements IEditorContributi
this._postPasteWidgetManager.clear();
}
private arePasteActionsEnabled(model: ITextModel): boolean {
if (this._configurationService.getValue('editor.experimental.pasteActions.enabled', { resource: model.uri })) {
return true;
}
// TODO: This check is only here to support enabling `ipynb.pasteImagesAsAttachments.enabled` by default
return model.uri.scheme === Schemas.vscodeNotebookCell;
private isPasteAsEnabled(): boolean {
return this._editor.getOption(EditorOption.pasteAs).enabled;
}
private handleCopy(e: ClipboardEvent) {
@ -110,7 +102,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
return;
}
if (!this.arePasteActionsEnabled(model)) {
if (!this.isPasteAsEnabled()) {
return;
}
@ -174,7 +166,7 @@ export class CopyPasteController extends Disposable implements IEditorContributi
}
const model = this._editor.getModel();
if (!this.arePasteActionsEnabled(model)) {
if (!this.isPasteAsEnabled()) {
return;
}
@ -232,7 +224,8 @@ export class CopyPasteController extends Disposable implements IEditorContributi
}
if (providerEdits.length) {
return this._postPasteWidgetManager.applyEditAndShowIfNeeded(selections[0], { activeEditIndex: 0, allEdits: providerEdits }, tokenSource.token);
const canShowWidget = editor.getOption(EditorOption.pasteAs).showPasteSelector === 'afterPaste';
return this._postPasteWidgetManager.applyEditAndShowIfNeeded(selections[0], { activeEditIndex: 0, allEdits: providerEdits }, canShowWidget, tokenSource.token);
}
await this.applyDefaultPasteHandler(dataTransfer, metadata, tokenSource.token);

View file

@ -9,6 +9,7 @@ import { VSDataTransfer } from 'vs/base/common/dataTransfer';
import { Disposable } 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';
import { IPosition } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
@ -110,7 +111,9 @@ export class DropIntoEditorController extends Disposable implements IEditorContr
if (possibleDropEdits) {
const allEdits = coalesce(possibleDropEdits);
// Pass in the parent token here as it tracks cancelling the entire drop operation.
await this._postDropWidgetManager.applyEditAndShowIfNeeded(Range.fromPositions(position), { activeEditIndex: 0, allEdits }, token);
const canShowWidget = editor.getOption(EditorOption.dropIntoEditor).showDropSelector === 'afterDrop';
await this._postDropWidgetManager.applyEditAndShowIfNeeded(Range.fromPositions(position), { activeEditIndex: 0, allEdits }, canShowWidget, token);
}
} finally {
tokenSource.dispose();

View file

@ -155,7 +155,7 @@ export class PostEditWidgetManager extends Disposable {
)(() => this.clear()));
}
public async applyEditAndShowIfNeeded(range: Range, edits: EditSet, token: CancellationToken) {
public async applyEditAndShowIfNeeded(range: Range, edits: EditSet, canShowWidget: boolean, token: CancellationToken) {
const model = this._editor.getModel();
if (!model) {
return;
@ -192,7 +192,7 @@ export class PostEditWidgetManager extends Disposable {
model.deltaDecorations(editTrackingDecoration, []);
}
if (editResult.isApplied && edits.allEdits.length > 1) {
if (canShowWidget && editResult.isApplied && edits.allEdits.length > 1) {
this.show(editRange ?? range, edits, async (newEditIndex) => {
const model = this._editor.getModel();
if (!model) {
@ -200,7 +200,7 @@ export class PostEditWidgetManager extends Disposable {
}
await model.undo();
this.applyEditAndShowIfNeeded(range, { activeEditIndex: newEditIndex, allEdits: edits.allEdits }, token);
this.applyEditAndShowIfNeeded(range, { activeEditIndex: newEditIndex, allEdits: edits.allEdits }, canShowWidget, token);
});
}
}

142
src/vs/monaco.d.ts vendored
View file

@ -3770,6 +3770,10 @@ declare namespace monaco.editor {
* When enabled, this shows a preview of the drop location and triggers an `onDropIntoEditor` event.
*/
dropIntoEditor?: IDropIntoEditorOptions;
/**
* Controls support for changing how content is pasted into the editor.
*/
pasteAs?: IPasteAsOptions;
/**
* Controls whether the editor receives tabs or defers them to the workbench for navigation.
*/
@ -4709,6 +4713,22 @@ declare namespace monaco.editor {
showDropSelector?: 'afterDrop' | 'never';
}
/**
* Configuration options for editor pasting as into behavior
*/
export interface IPasteAsOptions {
/**
* Enable paste as functionality in editors.
* Defaults to true.
*/
enabled?: boolean;
/**
* Controls if a widget is shown after a drop.
* Defaults to 'afterPaste'.
*/
showPasteSelector?: 'afterPaste' | 'never';
}
export enum EditorOption {
acceptSuggestionOnCommitCharacter = 0,
acceptSuggestionOnEnter = 1,
@ -4792,66 +4812,67 @@ declare namespace monaco.editor {
overviewRulerBorder = 79,
overviewRulerLanes = 80,
padding = 81,
parameterHints = 82,
peekWidgetDefaultFocus = 83,
definitionLinkOpensInPeek = 84,
quickSuggestions = 85,
quickSuggestionsDelay = 86,
readOnly = 87,
renameOnType = 88,
renderControlCharacters = 89,
renderFinalNewline = 90,
renderLineHighlight = 91,
renderLineHighlightOnlyWhenFocus = 92,
renderValidationDecorations = 93,
renderWhitespace = 94,
revealHorizontalRightPadding = 95,
roundedSelection = 96,
rulers = 97,
scrollbar = 98,
scrollBeyondLastColumn = 99,
scrollBeyondLastLine = 100,
scrollPredominantAxis = 101,
selectionClipboard = 102,
selectionHighlight = 103,
selectOnLineNumbers = 104,
showFoldingControls = 105,
showUnused = 106,
snippetSuggestions = 107,
smartSelect = 108,
smoothScrolling = 109,
stickyScroll = 110,
stickyTabStops = 111,
stopRenderingLineAfter = 112,
suggest = 113,
suggestFontSize = 114,
suggestLineHeight = 115,
suggestOnTriggerCharacters = 116,
suggestSelection = 117,
tabCompletion = 118,
tabIndex = 119,
unicodeHighlighting = 120,
unusualLineTerminators = 121,
useShadowDOM = 122,
useTabStops = 123,
wordBreak = 124,
wordSeparators = 125,
wordWrap = 126,
wordWrapBreakAfterCharacters = 127,
wordWrapBreakBeforeCharacters = 128,
wordWrapColumn = 129,
wordWrapOverride1 = 130,
wordWrapOverride2 = 131,
wrappingIndent = 132,
wrappingStrategy = 133,
showDeprecated = 134,
inlayHints = 135,
editorClassName = 136,
pixelRatio = 137,
tabFocusMode = 138,
layoutInfo = 139,
wrappingInfo = 140,
defaultColorDecorators = 141
pasteAs = 82,
parameterHints = 83,
peekWidgetDefaultFocus = 84,
definitionLinkOpensInPeek = 85,
quickSuggestions = 86,
quickSuggestionsDelay = 87,
readOnly = 88,
renameOnType = 89,
renderControlCharacters = 90,
renderFinalNewline = 91,
renderLineHighlight = 92,
renderLineHighlightOnlyWhenFocus = 93,
renderValidationDecorations = 94,
renderWhitespace = 95,
revealHorizontalRightPadding = 96,
roundedSelection = 97,
rulers = 98,
scrollbar = 99,
scrollBeyondLastColumn = 100,
scrollBeyondLastLine = 101,
scrollPredominantAxis = 102,
selectionClipboard = 103,
selectionHighlight = 104,
selectOnLineNumbers = 105,
showFoldingControls = 106,
showUnused = 107,
snippetSuggestions = 108,
smartSelect = 109,
smoothScrolling = 110,
stickyScroll = 111,
stickyTabStops = 112,
stopRenderingLineAfter = 113,
suggest = 114,
suggestFontSize = 115,
suggestLineHeight = 116,
suggestOnTriggerCharacters = 117,
suggestSelection = 118,
tabCompletion = 119,
tabIndex = 120,
unicodeHighlighting = 121,
unusualLineTerminators = 122,
useShadowDOM = 123,
useTabStops = 124,
wordBreak = 125,
wordSeparators = 126,
wordWrap = 127,
wordWrapBreakAfterCharacters = 128,
wordWrapBreakBeforeCharacters = 129,
wordWrapColumn = 130,
wordWrapOverride1 = 131,
wordWrapOverride2 = 132,
wrappingIndent = 133,
wrappingStrategy = 134,
showDeprecated = 135,
inlayHints = 136,
editorClassName = 137,
pixelRatio = 138,
tabFocusMode = 139,
layoutInfo = 140,
wrappingInfo = 141,
defaultColorDecorators = 142
}
export const EditorOptions: {
@ -4938,6 +4959,7 @@ declare namespace monaco.editor {
overviewRulerBorder: IEditorOption<EditorOption.overviewRulerBorder, boolean>;
overviewRulerLanes: IEditorOption<EditorOption.overviewRulerLanes, number>;
padding: IEditorOption<EditorOption.padding, Readonly<Required<IEditorPaddingOptions>>>;
pasteAs: IEditorOption<EditorOption.pasteAs, Readonly<Required<IPasteAsOptions>>>;
parameterHints: IEditorOption<EditorOption.parameterHints, Readonly<Required<IEditorParameterHintOptions>>>;
peekWidgetDefaultFocus: IEditorOption<EditorOption.peekWidgetDefaultFocus, 'tree' | 'editor'>;
definitionLinkOpensInPeek: IEditorOption<EditorOption.definitionLinkOpensInPeek, boolean>;