@@ -10,14 +10,15 @@ import { ApplyEditsResult, EndOfLinePreference, FindMatch, IInternalModelContent
1010import { PieceTreeBase , StringBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase' ;
1111import { SearchData } from 'vs/editor/common/model/textModelSearch' ;
1212import { countEOL , StringEOL } from 'vs/editor/common/model/tokensStore' ;
13+ import { TextChange } from 'vs/editor/common/model/textChange' ;
1314
1415export interface IValidatedEditOperation {
1516 sortIndex : number ;
1617 identifier : ISingleEditOperationIdentifier | null ;
1718 range : Range ;
1819 rangeOffset : number ;
1920 rangeLength : number ;
20- text : string | null ;
21+ text : string ;
2122 eolCount : number ;
2223 firstLineLength : number ;
2324 lastLineLength : number ;
@@ -205,7 +206,7 @@ export class PieceTreeTextBuffer implements ITextBuffer {
205206 this . _pieceTree . setEOL ( newEOL ) ;
206207 }
207208
208- public applyEdits ( rawOperations : ValidAnnotatedEditOperation [ ] , recordTrimAutoWhitespace : boolean ) : ApplyEditsResult {
209+ public applyEdits ( rawOperations : ValidAnnotatedEditOperation [ ] , recordTrimAutoWhitespace : boolean , computeUndoEdits : boolean ) : ApplyEditsResult {
209210 let mightContainRTL = this . _mightContainRTL ;
210211 let mightContainNonBasicASCII = this . _mightContainNonBasicASCII ;
211212 let canReduceOperations = true ;
@@ -225,7 +226,7 @@ export class PieceTreeTextBuffer implements ITextBuffer {
225226 mightContainNonBasicASCII = ! strings . isBasicASCII ( op . text ) ;
226227 }
227228
228- let validText : string | null = null ;
229+ let validText = '' ;
229230 let eolCount = 0 ;
230231 let firstLineLength = 0 ;
231232 let lastLineLength = 0 ;
@@ -260,66 +261,75 @@ export class PieceTreeTextBuffer implements ITextBuffer {
260261 // Sort operations ascending
261262 operations . sort ( PieceTreeTextBuffer . _sortOpsAscending ) ;
262263
263- let hasTouchingRanges = false ;
264- for ( let i = 0 , count = operations . length - 1 ; i < count ; i ++ ) {
265- let rangeEnd = operations [ i ] . range . getEndPosition ( ) ;
266- let nextRangeStart = operations [ i + 1 ] . range . getStartPosition ( ) ;
267-
268- if ( nextRangeStart . isBeforeOrEqual ( rangeEnd ) ) {
269- if ( nextRangeStart . isBefore ( rangeEnd ) ) {
270- // overlapping ranges
271- throw new Error ( 'Overlapping ranges are not allowed!' ) ;
272- }
273- hasTouchingRanges = true ;
274- }
275- }
276-
277264 if ( canReduceOperations ) {
278265 operations = this . _reduceOperations ( operations ) ;
279266 }
280267
281268 // Delta encode operations
282- let reverseRanges = PieceTreeTextBuffer . _getInverseEditRanges ( operations ) ;
269+ let reverseRanges = ( computeUndoEdits || recordTrimAutoWhitespace ? PieceTreeTextBuffer . _getInverseEditRanges ( operations ) : [ ] ) ;
283270 let newTrimAutoWhitespaceCandidates : { lineNumber : number , oldContent : string } [ ] = [ ] ;
284-
285- for ( let i = 0 ; i < operations . length ; i ++ ) {
286- let op = operations [ i ] ;
287- let reverseRange = reverseRanges [ i ] ;
288-
289- if ( recordTrimAutoWhitespace && op . isAutoWhitespaceEdit && op . range . isEmpty ( ) ) {
290- // Record already the future line numbers that might be auto whitespace removal candidates on next edit
291- for ( let lineNumber = reverseRange . startLineNumber ; lineNumber <= reverseRange . endLineNumber ; lineNumber ++ ) {
292- let currentLineContent = '' ;
293- if ( lineNumber === reverseRange . startLineNumber ) {
294- currentLineContent = this . getLineContent ( op . range . startLineNumber ) ;
295- if ( strings . firstNonWhitespaceIndex ( currentLineContent ) !== - 1 ) {
296- continue ;
271+ if ( recordTrimAutoWhitespace ) {
272+ for ( let i = 0 ; i < operations . length ; i ++ ) {
273+ let op = operations [ i ] ;
274+ let reverseRange = reverseRanges [ i ] ;
275+
276+ if ( op . isAutoWhitespaceEdit && op . range . isEmpty ( ) ) {
277+ // Record already the future line numbers that might be auto whitespace removal candidates on next edit
278+ for ( let lineNumber = reverseRange . startLineNumber ; lineNumber <= reverseRange . endLineNumber ; lineNumber ++ ) {
279+ let currentLineContent = '' ;
280+ if ( lineNumber === reverseRange . startLineNumber ) {
281+ currentLineContent = this . getLineContent ( op . range . startLineNumber ) ;
282+ if ( strings . firstNonWhitespaceIndex ( currentLineContent ) !== - 1 ) {
283+ continue ;
284+ }
297285 }
286+ newTrimAutoWhitespaceCandidates . push ( { lineNumber : lineNumber , oldContent : currentLineContent } ) ;
298287 }
299- newTrimAutoWhitespaceCandidates . push ( { lineNumber : lineNumber , oldContent : currentLineContent } ) ;
300288 }
301289 }
302290 }
303291
304292 let reverseOperations : IReverseSingleEditOperation [ ] = [ ] ;
305- for ( let i = 0 ; i < operations . length ; i ++ ) {
306- let op = operations [ i ] ;
307- let reverseRange = reverseRanges [ i ] ;
293+ if ( computeUndoEdits ) {
308294
309- reverseOperations [ i ] = {
310- sortIndex : op . sortIndex ,
311- identifier : op . identifier ,
312- range : reverseRange ,
313- text : this . getValueInRange ( op . range ) ,
314- forceMoveMarkers : op . forceMoveMarkers
315- } ;
316- }
295+ let hasTouchingRanges = false ;
296+ for ( let i = 0 , count = operations . length - 1 ; i < count ; i ++ ) {
297+ let rangeEnd = operations [ i ] . range . getEndPosition ( ) ;
298+ let nextRangeStart = operations [ i + 1 ] . range . getStartPosition ( ) ;
299+
300+ if ( nextRangeStart . isBeforeOrEqual ( rangeEnd ) ) {
301+ if ( nextRangeStart . isBefore ( rangeEnd ) ) {
302+ // overlapping ranges
303+ throw new Error ( 'Overlapping ranges are not allowed!' ) ;
304+ }
305+ hasTouchingRanges = true ;
306+ }
307+ }
317308
318- // Can only sort reverse operations when the order is not significant
319- if ( ! hasTouchingRanges ) {
320- reverseOperations . sort ( ( a , b ) => a . sortIndex - b . sortIndex ) ;
309+ let reverseRangeDeltaOffset = 0 ;
310+ for ( let i = 0 ; i < operations . length ; i ++ ) {
311+ const op = operations [ i ] ;
312+ const reverseRange = reverseRanges [ i ] ;
313+ const bufferText = this . getValueInRange ( op . range ) ;
314+ const reverseRangeOffset = op . rangeOffset + reverseRangeDeltaOffset ;
315+ reverseRangeDeltaOffset += ( op . text . length - bufferText . length ) ;
316+
317+ reverseOperations [ i ] = {
318+ sortIndex : op . sortIndex ,
319+ identifier : op . identifier ,
320+ range : reverseRange ,
321+ text : bufferText ,
322+ textChange : new TextChange ( op . rangeOffset , bufferText , reverseRangeOffset , op . text )
323+ } ;
324+ }
325+
326+ // Can only sort reverse operations when the order is not significant
327+ if ( ! hasTouchingRanges ) {
328+ reverseOperations . sort ( ( a , b ) => a . sortIndex - b . sortIndex ) ;
329+ }
321330 }
322331
332+
323333 this . _mightContainRTL = mightContainRTL ;
324334 this . _mightContainNonBasicASCII = mightContainNonBasicASCII ;
325335
@@ -393,7 +403,7 @@ export class PieceTreeTextBuffer implements ITextBuffer {
393403 result . push ( this . getValueInRange ( new Range ( lastEndLineNumber , lastEndColumn , range . startLineNumber , range . startColumn ) ) ) ;
394404
395405 // (2) -- Push new text
396- if ( operation . text ) {
406+ if ( operation . text . length > 0 ) {
397407 result . push ( operation . text ) ;
398408 }
399409
@@ -433,17 +443,15 @@ export class PieceTreeTextBuffer implements ITextBuffer {
433443 const endLineNumber = op . range . endLineNumber ;
434444 const endColumn = op . range . endColumn ;
435445
436- if ( startLineNumber === endLineNumber && startColumn === endColumn && ( ! op . text || op . text . length === 0 ) ) {
446+ if ( startLineNumber === endLineNumber && startColumn === endColumn && op . text . length === 0 ) {
437447 // no-op
438448 continue ;
439449 }
440450
441- const text = op . text ? op . text : '' ;
442-
443- if ( text ) {
451+ if ( op . text ) {
444452 // replacement
445453 this . _pieceTree . delete ( op . rangeOffset , op . rangeLength ) ;
446- this . _pieceTree . insert ( op . rangeOffset , text , true ) ;
454+ this . _pieceTree . insert ( op . rangeOffset , op . text , true ) ;
447455
448456 } else {
449457 // deletion
@@ -454,7 +462,7 @@ export class PieceTreeTextBuffer implements ITextBuffer {
454462 contentChanges . push ( {
455463 range : contentChangeRange ,
456464 rangeLength : op . rangeLength ,
457- text : text ,
465+ text : op . text ,
458466 rangeOffset : op . rangeOffset ,
459467 forceMoveMarkers : op . forceMoveMarkers
460468 } ) ;
@@ -503,7 +511,7 @@ export class PieceTreeTextBuffer implements ITextBuffer {
503511
504512 let resultRange : Range ;
505513
506- if ( op . text && op . text . length > 0 ) {
514+ if ( op . text . length > 0 ) {
507515 // the operation inserts something
508516 const lineCount = op . eolCount + 1 ;
509517
0 commit comments