Skip to content

Commit 94e8ae2

Browse files
authored
Merge pull request #286507 from microsoft/alexd/revert-paste-stable
Revert editor pasting to previous stable
2 parents 587d463 + c4d41c9 commit 94e8ae2

File tree

6 files changed

+84
-113
lines changed

6 files changed

+84
-113
lines changed

src/vs/editor/browser/controller/editContext/clipboardUtils.ts

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -83,42 +83,6 @@ function getDataToCopy(viewModel: IViewModel, modelSelections: Range[], emptySel
8383
return dataToCopy;
8484
}
8585

86-
export interface IPasteData {
87-
text: string;
88-
pasteOnNewLine: boolean;
89-
multicursorText: string[] | null;
90-
mode: string | null;
91-
}
92-
93-
export function computePasteData(e: ClipboardEvent, context: ViewContext, logService: ILogService): IPasteData | undefined {
94-
e.preventDefault();
95-
if (!e.clipboardData) {
96-
return;
97-
}
98-
let [text, metadata] = ClipboardEventUtils.getTextData(e.clipboardData);
99-
logService.trace('computePasteData with id : ', metadata?.id, ' with text.length: ', text.length);
100-
if (!text) {
101-
return;
102-
}
103-
PasteOptions.electronBugWorkaroundPasteEventHasFired = true;
104-
logService.trace('(computePasteData) PasteOptions.electronBugWorkaroundPasteEventHasFired : ', PasteOptions.electronBugWorkaroundPasteEventHasFired);
105-
metadata = metadata || InMemoryClipboardMetadataManager.INSTANCE.get(text);
106-
return getPasteDataFromMetadata(text, metadata, context);
107-
}
108-
109-
export function getPasteDataFromMetadata(text: string, metadata: ClipboardStoredMetadata | null, context: ViewContext): IPasteData {
110-
let pasteOnNewLine = false;
111-
let multicursorText: string[] | null = null;
112-
let mode: string | null = null;
113-
if (metadata) {
114-
const options = context.configuration.options;
115-
const emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard);
116-
pasteOnNewLine = emptySelectionClipboard && !!metadata.isFromEmptySelection;
117-
multicursorText = typeof metadata.multicursorText !== 'undefined' ? metadata.multicursorText : null;
118-
mode = metadata.mode;
119-
}
120-
return { text, pasteOnNewLine, multicursorText, mode };
121-
}
12286
/**
12387
* Every time we write to the clipboard, we record a bit of extra metadata here.
12488
* Every time we read from the cipboard, if the text matches our last written text,
@@ -168,11 +132,6 @@ export const CopyOptions = {
168132
electronBugWorkaroundCopyEventHasFired: false
169133
};
170134

171-
export const PasteOptions = {
172-
electronBugWorkaroundPasteEventHasFired: false,
173-
electronBugWorkaroundPasteEventLock: false
174-
};
175-
176135
interface InMemoryClipboardMetadata {
177136
lastCopiedValue: string;
178137
data: ClipboardStoredMetadata;

src/vs/editor/browser/controller/editContext/native/nativeEditContext.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { ViewConfigurationChangedEvent, ViewCursorStateChangedEvent, ViewDecorat
1616
import { ViewContext } from '../../../../common/viewModel/viewContext.js';
1717
import { RestrictedRenderingContext, RenderingContext, HorizontalPosition } from '../../../view/renderingContext.js';
1818
import { ViewController } from '../../../view/viewController.js';
19-
import { ensureClipboardGetsEditorSelection, computePasteData } from '../clipboardUtils.js';
19+
import { ClipboardEventUtils, ensureClipboardGetsEditorSelection, InMemoryClipboardMetadataManager } from '../clipboardUtils.js';
2020
import { AbstractEditContext } from '../editContext.js';
2121
import { editContextAddDisposableListener, FocusTracker, ITypeData } from './nativeEditContextUtils.js';
2222
import { ScreenReaderSupport } from './screenReaderSupport.js';
@@ -141,12 +141,28 @@ export class NativeEditContext extends AbstractEditContext {
141141
}));
142142
this._register(addDisposableListener(this.domNode.domNode, 'paste', (e) => {
143143
this.logService.trace('NativeEditContext#paste');
144-
const pasteData = computePasteData(e, this._context, this.logService);
145-
if (!pasteData) {
144+
e.preventDefault();
145+
if (!e.clipboardData) {
146146
return;
147147
}
148+
let [text, metadata] = ClipboardEventUtils.getTextData(e.clipboardData);
149+
this.logService.trace('NativeEditContext#paste with id : ', metadata?.id, ' with text.length: ', text.length);
150+
if (!text) {
151+
return;
152+
}
153+
metadata = metadata || InMemoryClipboardMetadataManager.INSTANCE.get(text);
154+
let pasteOnNewLine = false;
155+
let multicursorText: string[] | null = null;
156+
let mode: string | null = null;
157+
if (metadata) {
158+
const options = this._context.configuration.options;
159+
const emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard);
160+
pasteOnNewLine = emptySelectionClipboard && !!metadata.isFromEmptySelection;
161+
multicursorText = typeof metadata.multicursorText !== 'undefined' ? metadata.multicursorText : null;
162+
mode = metadata.mode;
163+
}
148164
this.logService.trace('NativeEditContext#paste (before viewController.paste)');
149-
this._viewController.paste(pasteData.text, pasteData.pasteOnNewLine, pasteData.multicursorText, pasteData.mode);
165+
this._viewController.paste(text, pasteOnNewLine, multicursorText, mode);
150166
}));
151167

152168
// Edit context events

src/vs/editor/browser/controller/editContext/textArea/textAreaEditContext.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@ import { IME } from '../../../../../base/common/ime.js';
3535
import { IKeybindingService } from '../../../../../platform/keybinding/common/keybinding.js';
3636
import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
3737
import { AbstractEditContext } from '../editContext.js';
38-
import { ICompositionData, ITextAreaInputHost, TextAreaInput, TextAreaWrapper } from './textAreaEditContextInput.js';
38+
import { ICompositionData, IPasteData, ITextAreaInputHost, TextAreaInput, TextAreaWrapper } from './textAreaEditContextInput.js';
3939
import { ariaLabelForScreenReaderContent, newlinecount, SimplePagedScreenReaderStrategy } from '../screenReaderUtils.js';
4040
import { _debugComposition, ITypeData, TextAreaState } from './textAreaEditContextState.js';
4141
import { getMapForWordSeparators, WordCharacterClass } from '../../../../common/core/wordCharacterClassifier.js';
4242
import { TextAreaEditContextRegistry } from './textAreaEditContextRegistry.js';
43-
import { IPasteData } from '../clipboardUtils.js';
4443

4544
export interface IVisibleRangeProvider {
4645
visibleRangeForPosition(position: Position): HorizontalPosition | null;
@@ -126,6 +125,7 @@ export class TextAreaEditContext extends AbstractEditContext {
126125
private _contentWidth: number;
127126
private _contentHeight: number;
128127
private _fontInfo: FontInfo;
128+
private _emptySelectionClipboard: boolean;
129129

130130
/**
131131
* Defined only when the text area is visible (composition case).
@@ -168,6 +168,7 @@ export class TextAreaEditContext extends AbstractEditContext {
168168
this._contentWidth = layoutInfo.contentWidth;
169169
this._contentHeight = layoutInfo.height;
170170
this._fontInfo = options.get(EditorOption.fontInfo);
171+
this._emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard);
171172

172173
this._visibleTextArea = null;
173174
this._selections = [new Selection(1, 1, 1, 1)];
@@ -285,7 +286,15 @@ export class TextAreaEditContext extends AbstractEditContext {
285286
}));
286287

287288
this._register(this._textAreaInput.onPaste((e: IPasteData) => {
288-
this._viewController.paste(e.text, e.pasteOnNewLine, e.multicursorText, e.mode);
289+
let pasteOnNewLine = false;
290+
let multicursorText: string[] | null = null;
291+
let mode: string | null = null;
292+
if (e.metadata) {
293+
pasteOnNewLine = (this._emptySelectionClipboard && !!e.metadata.isFromEmptySelection);
294+
multicursorText = (typeof e.metadata.multicursorText !== 'undefined' ? e.metadata.multicursorText : null);
295+
mode = e.metadata.mode;
296+
}
297+
this._viewController.paste(e.text, pasteOnNewLine, multicursorText, mode);
289298
}));
290299

291300
this._register(this._textAreaInput.onCut(() => {
@@ -562,6 +571,7 @@ export class TextAreaEditContext extends AbstractEditContext {
562571
this._contentWidth = layoutInfo.contentWidth;
563572
this._contentHeight = layoutInfo.height;
564573
this._fontInfo = options.get(EditorOption.fontInfo);
574+
this._emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard);
565575
this.textArea.setAttribute('wrap', this._textAreaWrapping && !this._visibleTextArea ? 'on' : 'off');
566576
const { tabSize } = this._context.viewModel.model.getOptions();
567577
this.textArea.domNode.style.tabSize = `${tabSize * this._fontInfo.spaceWidth}px`;

src/vs/editor/browser/controller/editContext/textArea/textAreaEditContextInput.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { Position } from '../../../../common/core/position.js';
1818
import { Selection } from '../../../../common/core/selection.js';
1919
import { IAccessibilityService } from '../../../../../platform/accessibility/common/accessibility.js';
2020
import { ILogService } from '../../../../../platform/log/common/log.js';
21-
import { ensureClipboardGetsEditorSelection, computePasteData, InMemoryClipboardMetadataManager, IPasteData, getPasteDataFromMetadata } from '../clipboardUtils.js';
21+
import { ClipboardEventUtils, ClipboardStoredMetadata, ensureClipboardGetsEditorSelection, InMemoryClipboardMetadataManager } from '../clipboardUtils.js';
2222
import { _debugComposition, ITextAreaWrapper, ITypeData, TextAreaState } from './textAreaEditContextState.js';
2323
import { ViewContext } from '../../../../common/viewModel/viewContext.js';
2424

@@ -30,6 +30,12 @@ export interface ICompositionData {
3030
data: string;
3131
}
3232

33+
34+
export interface IPasteData {
35+
text: string;
36+
metadata: ClipboardStoredMetadata | null;
37+
}
38+
3339
export interface ITextAreaInputHost {
3440
readonly context: ViewContext | null;
3541
getScreenReaderContent(): TextAreaState;
@@ -338,12 +344,11 @@ export class TextAreaInput extends Disposable {
338344
|| typeInput.positionDelta !== 0
339345
) {
340346
// https://w3c.github.io/input-events/#interface-InputEvent-Attributes
341-
if (this._host.context && e.inputType === 'insertFromPaste') {
342-
this._onPaste.fire(getPasteDataFromMetadata(
343-
typeInput.text,
344-
InMemoryClipboardMetadataManager.INSTANCE.get(typeInput.text),
345-
this._host.context
346-
));
347+
if (e.inputType === 'insertFromPaste') {
348+
this._onPaste.fire({
349+
text: typeInput.text,
350+
metadata: InMemoryClipboardMetadataManager.INSTANCE.get(typeInput.text)
351+
});
347352
} else {
348353
this._onType.fire(typeInput);
349354
}
@@ -376,15 +381,27 @@ export class TextAreaInput extends Disposable {
376381
// Pretend here we touched the text area, as the `paste` event will most likely
377382
// result in a `selectionchange` event which we want to ignore
378383
this._textArea.setIgnoreSelectionChangeTime('received paste event');
379-
if (!this._host.context) {
384+
385+
e.preventDefault();
386+
387+
if (!e.clipboardData) {
380388
return;
381389
}
382-
const pasteData = computePasteData(e, this._host.context, this._logService);
383-
if (!pasteData) {
390+
391+
let [text, metadata] = ClipboardEventUtils.getTextData(e.clipboardData);
392+
this._logService.trace(`TextAreaInput#onPaste with id : `, metadata?.id, ' with text.length: ', text.length);
393+
if (!text) {
384394
return;
385395
}
396+
397+
// try the in-memory store
398+
metadata = metadata || InMemoryClipboardMetadataManager.INSTANCE.get(text);
399+
386400
this._logService.trace(`TextAreaInput#onPaste (before onPaste)`);
387-
this._onPaste.fire(pasteData);
401+
this._onPaste.fire({
402+
text: text,
403+
metadata: metadata
404+
});
388405
}));
389406

390407
this._register(this._textArea.onFocus(() => {

src/vs/editor/contrib/clipboard/browser/clipboard.ts

Lines changed: 22 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextke
1414
import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js';
1515
import { KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';
1616
import { ILogService } from '../../../../platform/log/common/log.js';
17-
import { CopyOptions, generateDataToCopyAndStoreInMemory, InMemoryClipboardMetadataManager, PasteOptions } from '../../../browser/controller/editContext/clipboardUtils.js';
17+
import { CopyOptions, generateDataToCopyAndStoreInMemory, InMemoryClipboardMetadataManager } from '../../../browser/controller/editContext/clipboardUtils.js';
1818
import { NativeEditContextRegistry } from '../../../browser/controller/editContext/native/nativeEditContextRegistry.js';
1919
import { IActiveCodeEditor, ICodeEditor } from '../../../browser/editorBrowser.js';
2020
import { Command, EditorAction, MultiCommand, registerEditorAction } from '../../../browser/editorExtensions.js';
@@ -208,28 +208,6 @@ function executeClipboardCopyWithWorkaround(editor: IActiveCodeEditor, clipboard
208208
}
209209
}
210210

211-
async function pasteWithNavigatorAPI(editor: IActiveCodeEditor, clipboardService: IClipboardService, logService: ILogService): Promise<void> {
212-
const clipboardText = await clipboardService.readText();
213-
if (clipboardText !== '') {
214-
const metadata = InMemoryClipboardMetadataManager.INSTANCE.get(clipboardText);
215-
let pasteOnNewLine = false;
216-
let multicursorText: string[] | null = null;
217-
let mode: string | null = null;
218-
if (metadata) {
219-
pasteOnNewLine = (editor.getOption(EditorOption.emptySelectionClipboard) && !!metadata.isFromEmptySelection);
220-
multicursorText = (typeof metadata.multicursorText !== 'undefined' ? metadata.multicursorText : null);
221-
mode = metadata.mode;
222-
}
223-
logService.trace('pasteWithNavigatorAPI with id : ', metadata?.id, ', clipboardText.length : ', clipboardText.length);
224-
editor.trigger('keyboard', Handler.Paste, {
225-
text: clipboardText,
226-
pasteOnNewLine,
227-
multicursorText,
228-
mode
229-
});
230-
}
231-
}
232-
233211
function registerExecCommandImpl(target: MultiCommand | undefined, browserCommand: 'cut' | 'copy'): void {
234212
if (!target) {
235213
return;
@@ -317,25 +295,10 @@ if (PasteAction) {
317295
}
318296

319297
logService.trace('registerExecCommandImpl (before triggerPaste)');
320-
PasteOptions.electronBugWorkaroundPasteEventHasFired = false;
321-
logService.trace('(before triggerPaste) PasteOptions.electronBugWorkaroundPasteEventHasFired : ', PasteOptions.electronBugWorkaroundPasteEventHasFired);
322298
const triggerPaste = clipboardService.triggerPaste(getActiveWindow().vscodeWindowId);
323299
if (triggerPaste) {
324300
logService.trace('registerExecCommandImpl (triggerPaste defined)');
325-
PasteOptions.electronBugWorkaroundPasteEventLock = false;
326301
return triggerPaste.then(async () => {
327-
logService.trace('(triggerPaste) PasteOptions.electronBugWorkaroundPasteEventHasFired : ', PasteOptions.electronBugWorkaroundPasteEventHasFired);
328-
if (PasteOptions.electronBugWorkaroundPasteEventHasFired === false) {
329-
// Ensure this doesn't run twice, what appears to be happening is
330-
// triggerPasteis called once but it's handler is called multiple times
331-
// when it reproduces
332-
logService.trace('(triggerPaste) PasteOptions.electronBugWorkaroundPasteEventLock : ', PasteOptions.electronBugWorkaroundPasteEventLock);
333-
if (PasteOptions.electronBugWorkaroundPasteEventLock === true) {
334-
return;
335-
}
336-
PasteOptions.electronBugWorkaroundPasteEventLock = true;
337-
return pasteWithNavigatorAPI(focusedEditor, clipboardService, logService);
338-
}
339302
logService.trace('registerExecCommandImpl (after triggerPaste)');
340303
return CopyPasteController.get(focusedEditor)?.finishedPaste() ?? Promise.resolve();
341304
});
@@ -345,7 +308,27 @@ if (PasteAction) {
345308
if (platform.isWeb) {
346309
logService.trace('registerExecCommandImpl (Paste handling on web)');
347310
// Use the clipboard service if document.execCommand('paste') was not successful
348-
return pasteWithNavigatorAPI(focusedEditor, clipboardService, logService);
311+
return (async () => {
312+
const clipboardText = await clipboardService.readText();
313+
if (clipboardText !== '') {
314+
const metadata = InMemoryClipboardMetadataManager.INSTANCE.get(clipboardText);
315+
let pasteOnNewLine = false;
316+
let multicursorText: string[] | null = null;
317+
let mode: string | null = null;
318+
if (metadata) {
319+
pasteOnNewLine = (focusedEditor.getOption(EditorOption.emptySelectionClipboard) && !!metadata.isFromEmptySelection);
320+
multicursorText = (typeof metadata.multicursorText !== 'undefined' ? metadata.multicursorText : null);
321+
mode = metadata.mode;
322+
}
323+
logService.trace('registerExecCommandImpl (clipboardText.length : ', clipboardText.length, ' id : ', metadata?.id, ')');
324+
focusedEditor.trigger('keyboard', Handler.Paste, {
325+
text: clipboardText,
326+
pasteOnNewLine,
327+
multicursorText,
328+
mode
329+
});
330+
}
331+
})();
349332
}
350333
return true;
351334
}

0 commit comments

Comments
 (0)