@@ -140,6 +140,14 @@ export class SparseEncodedTokens {
140140 this . _tokenCount = tokens . length / 4 ;
141141 }
142142
143+ public toString ( startLineNumber : number ) : string {
144+ let pieces : string [ ] = [ ] ;
145+ for ( let i = 0 ; i < this . _tokenCount ; i ++ ) {
146+ pieces . push ( `(${ this . _getDeltaLine ( i ) + startLineNumber } ,${ this . _getStartCharacter ( i ) } -${ this . _getEndCharacter ( i ) } )` ) ;
147+ }
148+ return `[${ pieces . join ( ',' ) } ]` ;
149+ }
150+
143151 public getMaxDeltaLine ( ) : number {
144152 const tokenCount = this . _getTokenCount ( ) ;
145153 if ( tokenCount === 0 ) {
@@ -229,8 +237,8 @@ export class SparseEncodedTokens {
229237 const tokenMetadata = tokens [ srcOffset + 3 ] ;
230238
231239 if (
232- ( tokenDeltaLine > startDeltaLine || ( tokenDeltaLine === startDeltaLine && tokenStartCharacter >= startChar ) )
233- && ( tokenDeltaLine < endDeltaLine || ( tokenDeltaLine === endDeltaLine && tokenEndCharacter <= endChar ) )
240+ ( tokenDeltaLine > startDeltaLine || ( tokenDeltaLine === startDeltaLine && tokenEndCharacter >= startChar ) )
241+ && ( tokenDeltaLine < endDeltaLine || ( tokenDeltaLine === endDeltaLine && tokenStartCharacter <= endChar ) )
234242 ) {
235243 hasDeletedTokens = true ;
236244 } else {
@@ -254,6 +262,45 @@ export class SparseEncodedTokens {
254262 return firstDeltaLine ;
255263 }
256264
265+ public split ( startDeltaLine : number , startChar : number , endDeltaLine : number , endChar : number ) : [ SparseEncodedTokens , SparseEncodedTokens , number ] {
266+ const tokens = this . _tokens ;
267+ const tokenCount = this . _tokenCount ;
268+ let aTokens : number [ ] = [ ] ;
269+ let bTokens : number [ ] = [ ] ;
270+ let destTokens : number [ ] = aTokens ;
271+ let destOffset = 0 ;
272+ let destFirstDeltaLine : number = 0 ;
273+ for ( let i = 0 ; i < tokenCount ; i ++ ) {
274+ const srcOffset = 4 * i ;
275+ const tokenDeltaLine = tokens [ srcOffset ] ;
276+ const tokenStartCharacter = tokens [ srcOffset + 1 ] ;
277+ const tokenEndCharacter = tokens [ srcOffset + 2 ] ;
278+ const tokenMetadata = tokens [ srcOffset + 3 ] ;
279+
280+ if ( ( tokenDeltaLine > startDeltaLine || ( tokenDeltaLine === startDeltaLine && tokenEndCharacter >= startChar ) ) ) {
281+ if ( ( tokenDeltaLine < endDeltaLine || ( tokenDeltaLine === endDeltaLine && tokenStartCharacter <= endChar ) ) ) {
282+ // this token is touching the range
283+ continue ;
284+ } else {
285+ // this token is after the range
286+ if ( destTokens !== bTokens ) {
287+ // this token is the first token after the range
288+ destTokens = bTokens ;
289+ destOffset = 0 ;
290+ destFirstDeltaLine = tokenDeltaLine ;
291+ }
292+ }
293+ }
294+
295+ destTokens [ destOffset ++ ] = tokenDeltaLine - destFirstDeltaLine ;
296+ destTokens [ destOffset ++ ] = tokenStartCharacter ;
297+ destTokens [ destOffset ++ ] = tokenEndCharacter ;
298+ destTokens [ destOffset ++ ] = tokenMetadata ;
299+ }
300+
301+ return [ new SparseEncodedTokens ( new Uint32Array ( aTokens ) ) , new SparseEncodedTokens ( new Uint32Array ( bTokens ) ) , destFirstDeltaLine ] ;
302+ }
303+
257304 public acceptDeleteRange ( horizontalShiftForFirstLineTokens : number , startDeltaLine : number , startCharacter : number , endDeltaLine : number , endCharacter : number ) : void {
258305 // This is a bit complex, here are the cases I used to think about this:
259306 //
@@ -518,6 +565,10 @@ export class MultilineTokens2 {
518565 this . endLineNumber = this . startLineNumber + this . tokens . getMaxDeltaLine ( ) ;
519566 }
520567
568+ public toString ( ) : string {
569+ return this . tokens . toString ( this . startLineNumber ) ;
570+ }
571+
521572 private _updateEndLineNumber ( ) : void {
522573 this . endLineNumber = this . startLineNumber + this . tokens . getMaxDeltaLine ( ) ;
523574 }
@@ -549,6 +600,17 @@ export class MultilineTokens2 {
549600 this . _updateEndLineNumber ( ) ;
550601 }
551602
603+ public split ( range : Range ) : [ MultilineTokens2 , MultilineTokens2 ] {
604+ // split tokens to two:
605+ // a) all the tokens before `range`
606+ // b) all the tokens after `range`
607+ const startLineIndex = range . startLineNumber - this . startLineNumber ;
608+ const endLineIndex = range . endLineNumber - this . startLineNumber ;
609+
610+ const [ a , b , bDeltaLine ] = this . tokens . split ( startLineIndex , range . startColumn - 1 , endLineIndex , range . endColumn - 1 ) ;
611+ return [ new MultilineTokens2 ( this . startLineNumber , a ) , new MultilineTokens2 ( this . startLineNumber + bDeltaLine , b ) ] ;
612+ }
613+
552614 public applyEdit ( range : IRange , text : string ) : void {
553615 const [ eolCount , firstLineLength , lastLineLength ] = countEOL ( text ) ;
554616 this . acceptEdit ( range , eolCount , firstLineLength , lastLineLength , text . length > 0 ? text . charCodeAt ( 0 ) : CharCode . Null ) ;
@@ -837,32 +899,59 @@ export class TokensStore2 {
837899 return _range ;
838900 }
839901 const range = _range . plusRange ( _firstRange ) . plusRange ( _lastRange ) ;
840- let insertIndex = this . _pieces . length ;
902+ let insertPosition : { index : number ; } | null = null ;
841903 for ( let i = 0 , len = this . _pieces . length ; i < len ; i ++ ) {
842904 const piece = this . _pieces [ i ] ;
843905 if ( piece . endLineNumber < range . startLineNumber ) {
906+ // this piece is before the range
844907 continue ;
845908 }
909+
846910 if ( piece . startLineNumber > range . endLineNumber ) {
847- insertIndex = Math . min ( i , insertIndex ) ;
911+ // this piece is after the range, so mark the spot before this piece
912+ // as a good insertion position and stop looping
913+ insertPosition = insertPosition || { index : i } ;
848914 break ;
849915 }
916+
917+ // this piece might intersect with the range
850918 piece . removeTokens ( range ) ;
851919
852920 if ( piece . isEmpty ( ) ) {
921+ // remove the piece if it became empty
853922 this . _pieces . splice ( i , 1 ) ;
854923 i -- ;
855924 len -- ;
856- insertIndex -- ;
857925 continue ;
858926 }
859927
860- if ( piece . startLineNumber >= range . endLineNumber ) {
861- insertIndex = Math . min ( i , insertIndex ) ;
928+ if ( piece . endLineNumber < range . startLineNumber ) {
929+ // after removal, this piece is before the range
930+ continue ;
931+ }
932+
933+ if ( piece . startLineNumber > range . endLineNumber ) {
934+ // after removal, this piece is after the range
935+ insertPosition = insertPosition || { index : i } ;
936+ continue ;
862937 }
938+
939+ // after removal, this piece contains the range
940+ const [ a , b ] = piece . split ( range ) ;
941+ this . _pieces . splice ( i , 1 , a , b ) ;
942+ i ++ ;
943+ len ++ ;
944+
945+ insertPosition = insertPosition || { index : i } ;
863946 }
864947
865- this . _pieces = arrays . arrayInsert ( this . _pieces , insertIndex , pieces ) ;
948+ insertPosition = insertPosition || { index : this . _pieces . length } ;
949+
950+ this . _pieces = arrays . arrayInsert ( this . _pieces , insertPosition . index , pieces ) ;
951+
952+ // console.log(`I HAVE ${this._pieces.length} pieces`);
953+ // console.log(`${this._pieces.map(p => p.toString()).join(', ')}`);
954+
866955 return range ;
867956 }
868957
0 commit comments