提交 e07bba8d 编写于 作者: A Alex Dima

Keep track of what text got copied from what cursor and use that information...

Keep track of what text got copied from what cursor and use that information when pasting (fixes #4996)
上级 d589f2f1
......@@ -54,6 +54,7 @@ const canUseZeroSizeTextarea = (browser.isEdgeOrIE || browser.isFirefox);
interface LocalClipboardMetadata {
lastCopiedValue: string;
isFromEmptySelection: boolean;
multicursorText: string[];
}
/**
......@@ -161,15 +162,26 @@ export class TextAreaHandler extends ViewPart {
const textAreaInputHost: ITextAreaInputHost = {
getPlainTextToCopy: (): string => {
const whatToCopy = this._context.model.getPlainTextToCopy(this._selections, this._emptySelectionClipboard);
// When writing "LINE\r\n" to the clipboard and then pasting,
// Firefox pastes "LINE\n", so let's work around this quirk
const lastCopiedValue = (browser.isFirefox ? whatToCopy.replace(/\r\n/g, '\n') : whatToCopy);
const metadata: LocalClipboardMetadata = {
lastCopiedValue: lastCopiedValue,
isFromEmptySelection: (this._emptySelectionClipboard && this._selections.length === 1 && this._selections[0].isEmpty())
};
const rawWhatToCopy = this._context.model.getPlainTextToCopy(this._selections, this._emptySelectionClipboard);
const newLineCharacter = this._context.model.getEOL();
const isFromEmptySelection = (this._emptySelectionClipboard && this._selections.length === 1 && this._selections[0].isEmpty());
const multicursorText = (Array.isArray(rawWhatToCopy) ? rawWhatToCopy : null);
const whatToCopy = (Array.isArray(rawWhatToCopy) ? rawWhatToCopy.join(newLineCharacter) : rawWhatToCopy);
let metadata: LocalClipboardMetadata = null;
if (isFromEmptySelection || multicursorText) {
// Only store the non-default metadata
// When writing "LINE\r\n" to the clipboard and then pasting,
// Firefox pastes "LINE\n", so let's work around this quirk
const lastCopiedValue = (browser.isFirefox ? whatToCopy.replace(/\r\n/g, '\n') : whatToCopy);
metadata = {
lastCopiedValue: lastCopiedValue,
isFromEmptySelection: (this._emptySelectionClipboard && this._selections.length === 1 && this._selections[0].isEmpty()),
multicursorText: multicursorText
};
}
LocalClipboardMetadataManager.INSTANCE.set(metadata);
......@@ -228,10 +240,12 @@ export class TextAreaHandler extends ViewPart {
const metadata = LocalClipboardMetadataManager.INSTANCE.get(e.text);
let pasteOnNewLine = false;
let multicursorText: string[] = null;
if (metadata) {
pasteOnNewLine = (this._emptySelectionClipboard && metadata.isFromEmptySelection);
multicursorText = metadata.multicursorText;
}
this._viewController.paste('keyboard', e.text, pasteOnNewLine);
this._viewController.paste('keyboard', e.text, pasteOnNewLine, multicursorText);
}));
this._register(this._textAreaInput.onCut(() => {
......
......@@ -62,10 +62,11 @@ export class ViewController {
this._execCoreEditorCommandFunc(editorCommand, args);
}
public paste(source: string, text: string, pasteOnNewLine: boolean): void {
public paste(source: string, text: string, pasteOnNewLine: boolean, multicursorText: string[]): void {
this.commandService.executeCommand(editorCommon.Handler.Paste, {
text: text,
pasteOnNewLine: pasteOnNewLine,
multicursorText: multicursorText
});
}
......
......@@ -454,7 +454,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
case H.Paste:
cursorChangeReason = CursorChangeReason.Paste;
this._paste(<string>payload.text, <boolean>payload.pasteOnNewLine);
this._paste(<string>payload.text, <boolean>payload.pasteOnNewLine, <string[]>payload.multicursorText);
break;
case H.Cut:
......@@ -517,8 +517,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors {
this._executeEditOperation(TypeOperations.replacePreviousChar(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), text, replaceCharCnt));
}
private _paste(text: string, pasteOnNewLine: boolean): void {
this._executeEditOperation(TypeOperations.paste(this.context.config, this.context.model, this.getSelections(), pasteOnNewLine, text));
private _paste(text: string, pasteOnNewLine: boolean, multicursorText: string[]): void {
this._executeEditOperation(TypeOperations.paste(this.context.config, this.context.model, this.getSelections(), text, pasteOnNewLine, multicursorText));
}
private _cut(): void {
......
......@@ -109,7 +109,7 @@ export class TypeOperations {
});
}
private static _distributePasteToCursors(selections: Selection[], pasteOnNewLine: boolean, text: string): string[] {
private static _distributePasteToCursors(selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): string[] {
if (pasteOnNewLine) {
return null;
}
......@@ -118,6 +118,10 @@ export class TypeOperations {
return null;
}
if (multicursorText && multicursorText.length === selections.length) {
return multicursorText;
}
for (let i = 0; i < selections.length; i++) {
if (selections[i].startLineNumber !== selections[i].endLineNumber) {
return null;
......@@ -132,8 +136,8 @@ export class TypeOperations {
return pastePieces;
}
public static paste(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], pasteOnNewLine: boolean, text: string): EditOperationResult {
const distributedPaste = this._distributePasteToCursors(selections, pasteOnNewLine, text);
public static paste(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): EditOperationResult {
const distributedPaste = this._distributePasteToCursors(selections, text, pasteOnNewLine, multicursorText);
if (distributedPaste) {
selections = selections.sort(Range.compareRangesUsingStarts);
......
......@@ -144,7 +144,8 @@ export interface IViewModel {
validateModelPosition(modelPosition: IPosition): Position;
deduceModelPositionRelativeToViewPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position;
getPlainTextToCopy(ranges: Range[], emptySelectionClipboard: boolean): string;
getEOL(): string;
getPlainTextToCopy(ranges: Range[], emptySelectionClipboard: boolean): string | string[];
getHTMLToCopy(ranges: Range[], emptySelectionClipboard: boolean): string;
}
......
......@@ -428,7 +428,11 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
return this.model.getPositionAt(resultOffset);
}
public getPlainTextToCopy(ranges: Range[], emptySelectionClipboard: boolean): string {
public getEOL(): string {
return this.model.getEOL();
}
public getPlainTextToCopy(ranges: Range[], emptySelectionClipboard: boolean): string | string[] {
const newLineCharacter = this.model.getEOL();
ranges = ranges.slice(0);
......@@ -459,7 +463,7 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel
for (let i = 0; i < nonEmptyRanges.length; i++) {
result.push(this.getValueInRange(nonEmptyRanges[i], editorCommon.EndOfLinePreference.TextDefined));
}
return result.join(newLineCharacter);
return result.length === 1 ? result[0] : result;
}
public getHTMLToCopy(viewRanges: Range[], emptySelectionClipboard: boolean): string {
......
......@@ -1418,6 +1418,35 @@ suite('Editor Controller - Regression tests', () => {
});
});
test('issue #4996: Multiple cursor paste pastes contents of all cursors', () => {
usingCursor({
text: [
'line1',
'line2',
'line3'
],
}, (model, cursor) => {
cursor.setSelections('test', [new Selection(1, 1, 1, 1), new Selection(2, 1, 2, 1)]);
cursorCommand(cursor, H.Paste, {
text: 'a\nb\nc\nd',
pasteOnNewLine: false,
multicursorText: [
'a\nb',
'c\nd'
]
});
assert.equal(model.getValue(), [
'a',
'bline1',
'c',
'dline2',
'line3'
].join('\n'));
});
});
test('issue #3071: Investigate why undo stack gets corrupted', () => {
let model = Model.createFromString(
[
......
......@@ -42,10 +42,10 @@ suite('ViewModel', () => {
});
});
function assertGetPlainTextToCopy(text: string[], ranges: Range[], emptySelectionClipboard: boolean, expected: string): void {
function assertGetPlainTextToCopy(text: string[], ranges: Range[], emptySelectionClipboard: boolean, expected: string | string[]): void {
testViewModel(text, {}, (viewModel, model) => {
let actual = viewModel.getPlainTextToCopy(ranges, emptySelectionClipboard);
assert.equal(actual, expected);
assert.deepEqual(actual, expected);
});
}
......@@ -157,7 +157,7 @@ suite('ViewModel', () => {
new Range(3, 2, 3, 6),
],
false,
'ine2\nine3'
['ine2', 'ine3']
);
});
......@@ -169,7 +169,7 @@ suite('ViewModel', () => {
new Range(2, 2, 2, 6),
],
false,
'ine2\nine3'
['ine2', 'ine3']
);
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册