diff --git a/src/vs/editor/common/controller/textAreaState.ts b/src/vs/editor/common/controller/textAreaState.ts index 23ac8253b13..808c6a4c2df 100644 --- a/src/vs/editor/common/controller/textAreaState.ts +++ b/src/vs/editor/common/controller/textAreaState.ts @@ -163,7 +163,13 @@ export abstract class TextAreaState { if (currentSelectionStart === currentSelectionEnd) { // composition accept case // [blahblah] => blahblah| - if (previousValue === currentValue && previousSelectionStart === 0 && previousSelectionEnd === previousValue.length && currentSelectionStart === currentValue.length) { + if ( + previousValue === currentValue + && previousSelectionStart === 0 + && previousSelectionEnd === previousValue.length + && currentSelectionStart === currentValue.length + && currentValue.indexOf('\n') === -1 + ) { return { text: '', replaceCharCnt: 0 diff --git a/src/vs/editor/common/model/editableTextModel.ts b/src/vs/editor/common/model/editableTextModel.ts index c9f124d6e59..0c993916807 100644 --- a/src/vs/editor/common/model/editableTextModel.ts +++ b/src/vs/editor/common/model/editableTextModel.ts @@ -334,6 +334,9 @@ export class EditableTextModel extends TextModelWithDecorations implements Edito currentLineEdits: ILineEdit[] = [], currentLineNumber = 0; + var lastContentChangedVersionId = this.getVersionId(); + let lastContentChanged2VersionId = this.getVersionId(); + var adjustLineNumbers = (toLineNumber:number, delta:number): void => { // console.log('adjustLineNumbers: ' + toLineNumber + ' by ' + delta + ', lines.length: ' + this._lines.length); if (delta !== 0) { @@ -351,6 +354,7 @@ export class EditableTextModel extends TextModelWithDecorations implements Edito if (editLineNumber !== currentLineNumber) { if (currentLineEdits.length > 0) { this._applyLineEdits(deferredEventsBuilder, currentLineNumber, currentLineEdits); + lastContentChangedVersionId = this.getVersionId(); currentLineEdits = []; } currentLineNumber = editLineNumber; @@ -374,14 +378,13 @@ export class EditableTextModel extends TextModelWithDecorations implements Edito var r = 0; if (currentLineEdits.length > 0) { r = this._applyLineEdits(deferredEventsBuilder, currentLineNumber, currentLineEdits); + lastContentChangedVersionId = this.getVersionId(); currentLineEdits = []; } currentLineNumber = 0; return r; }; - let lastContentChanged2VersionId = this.getVersionId(); - let lastRealOpIndex = 0; for (let i = operations.length - 1; i >= 0; i--) { if (!operations[i].isNoOp) { @@ -483,6 +486,7 @@ export class EditableTextModel extends TextModelWithDecorations implements Edito this.emitModelContentChangedLineChangedEvent(spliceStart); this.emitModelContentChangedLinesDeletedEvent(spliceStart + 1, spliceStart + spliceCnt); + lastContentChangedVersionId = this.getVersionId(); // this.emitModelContentChangedLinesInsertedEvent(startLineNumber + editingLinesCnt + 1, startLineNumber + insertingLinesCnt, newLinesContent.join('\n')); } @@ -521,6 +525,7 @@ export class EditableTextModel extends TextModelWithDecorations implements Edito this._lines[startLineNumber + insertingLinesCnt - 1].append(deferredEventsBuilder.changedMarkers, leftoverLine); this.emitModelContentChangedLinesInsertedEvent(startLineNumber + editingLinesCnt + 1, startLineNumber + insertingLinesCnt, newLinesContent.join('\n')); + lastContentChangedVersionId = this.getVersionId(); } // console.log('~~~'); @@ -548,6 +553,10 @@ export class EditableTextModel extends TextModelWithDecorations implements Edito this._emitContentChanged2(seqEdit.range.startLineNumber, seqEdit.range.startColumn, seqEdit.range.endLineNumber, seqEdit.range.endColumn, seqEdit.rangeLength, seqEdit.text, this._isUndoing, this._isRedoing); } + if (this.getVersionId() > lastContentChangedVersionId) { + // TODO@Alex: need to rewrite the eventing logic + this.emitModelContentChangedLineChangedEventNoVersionBump(baseLineNumber); + } adjustLineNumbers(this._lines.length, deltaLines); }); @@ -687,8 +696,7 @@ export class EditableTextModel extends TextModelWithDecorations implements Edito } } - private emitModelContentChangedLineChangedEvent(lineNumber: number): void { - this._increaseVersionId(); + private emitModelContentChangedLineChangedEventNoVersionBump(lineNumber: number): void { var e:EditorCommon.IModelContentChangedLineChangedEvent = { changeType: EditorCommon.EventType.ModelContentChangedLineChanged, lineNumber: lineNumber, @@ -702,6 +710,11 @@ export class EditableTextModel extends TextModelWithDecorations implements Edito } } + private emitModelContentChangedLineChangedEvent(lineNumber: number): void { + this._increaseVersionId(); + this.emitModelContentChangedLineChangedEventNoVersionBump(lineNumber); + } + private emitModelContentChangedLinesDeletedEvent(fromLineNumber: number, toLineNumber: number): void { this._increaseVersionId(); var e:EditorCommon.IModelContentChangedLinesDeletedEvent = { diff --git a/src/vs/editor/test/common/controller/textAreaState.test.ts b/src/vs/editor/test/common/controller/textAreaState.test.ts index 281f75c41a4..4111d68323f 100644 --- a/src/vs/editor/test/common/controller/textAreaState.test.ts +++ b/src/vs/editor/test/common/controller/textAreaState.test.ts @@ -230,6 +230,15 @@ suite('TextAreaState', () => { ); }); + test('issue #2586: Replacing selected end-of-line with newline locks up the document', () => { + testDeduceInput( + new IENarratorTextAreaState(null, ']\n', 1, 2, false, 0), + ']\n', + 2, 2, false, + '\n', 0 + ); + }); + test('extractNewText - no previous state without selection', () => { testDeduceInput( null, diff --git a/src/vs/editor/test/common/model/editableTextModel.test.ts b/src/vs/editor/test/common/model/editableTextModel.test.ts index af35fdc1632..db3c404579a 100644 --- a/src/vs/editor/test/common/model/editableTextModel.test.ts +++ b/src/vs/editor/test/common/model/editableTextModel.test.ts @@ -1174,6 +1174,22 @@ suite('EditorModel - EditableTextModel.applyEdits', () => { ); }); + test('issue #2586 Replacing selected end-of-line with newline locks up the document', () => { + testApplyEdits( + [ + 'something', + 'interesting' + ], + [ + editOp(1, 10, 2, 1, ['', '']) + ], + [ + 'something', + 'interesting' + ] + ); + }); + function assertSyncedModels(text:string, callback:(model:EditableTextModel, assertMirrorModels:()=>void)=>void, setup:(model:EditableTextModel)=>void = null): void { var model = new EditableTextModel([], TextModel.toRawText(text), null); model.setEOL(EditorCommon.EndOfLineSequence.LF);