diff --git a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts index 27416907f49d69820bbd9442bd9f7d679f9b2732..7e5ad2bb133bca484455d2d803563a63227ecd90 100644 --- a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts +++ b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts @@ -206,13 +206,17 @@ export class PieceTreeTextBuffer implements ITextBuffer { // Sort operations ascending operations.sort(PieceTreeTextBuffer._sortOpsAscending); + let hasTouchingRanges = false; for (let i = 0, count = operations.length - 1; i < count; i++) { let rangeEnd = operations[i].range.getEndPosition(); let nextRangeStart = operations[i + 1].range.getStartPosition(); - if (nextRangeStart.isBefore(rangeEnd)) { - // overlapping ranges - throw new Error('Overlapping ranges are not allowed!'); + if (nextRangeStart.isBeforeOrEqual(rangeEnd)) { + if (nextRangeStart.isBefore(rangeEnd)) { + // overlapping ranges + throw new Error('Overlapping ranges are not allowed!'); + } + hasTouchingRanges = true; } } @@ -256,7 +260,11 @@ export class PieceTreeTextBuffer implements ITextBuffer { forceMoveMarkers: op.forceMoveMarkers }; } - reverseOperations.sort((a, b) => a.sortIndex - b.sortIndex); + + // Can only sort reverse operations when the order is not significant + if (!hasTouchingRanges) { + reverseOperations.sort((a, b) => a.sortIndex - b.sortIndex); + } this._mightContainRTL = mightContainRTL; this._mightContainNonBasicASCII = mightContainNonBasicASCII; diff --git a/src/vs/editor/test/common/model/editableTextModel.test.ts b/src/vs/editor/test/common/model/editableTextModel.test.ts index fa41d0d5f4956371412d4eb4ffd0a790e70aa970..480fdc82c4742526be1fb55aa5dccb9c1d7b03fb 100644 --- a/src/vs/editor/test/common/model/editableTextModel.test.ts +++ b/src/vs/editor/test/common/model/editableTextModel.test.ts @@ -1091,4 +1091,26 @@ suite('EditorModel - EditableTextModel.applyEdits', () => { model.dispose(); }); + + test('issue #48741: Broken undo stack with move lines up with multiple cursors', () => { + let model = createEditableTextModelFromString([ + 'line1', + 'line2', + 'line3', + '', + ].join('\n')); + + const undoEdits = model.applyEdits([ + { range: new Range(4, 1, 4, 1), text: 'line3', }, + { range: new Range(3, 1, 3, 6), text: null, }, + { range: new Range(2, 1, 3, 1), text: null, }, + { range: new Range(3, 6, 3, 6), text: '\nline2' } + ]); + + model.applyEdits(undoEdits); + + assert.deepEqual(model.getValue(), 'line1\nline2\nline3\n'); + + model.dispose(); + }); });