'use strict' ; import * as vscode from 'vscode' ; import * as textUtil from './text-util' ; export class RangeSet { private ranges : vscode . Range [ ] = [ ] ; public clear ( ) { this . ranges = [ ] ; this . ranges [ 0 ] . start . translate ( 0 , 0 ) ; } /** Adjust the ranges by the given delta */ public shiftDelta ( delta ) { this . ranges . forEach ( ( r , idx ) => { this . ranges [ idx ] = textUtil . rangeTranslate ( this . ranges [ idx ] , delta ) ; } ) ; } private getOverlappingIndices ( range , options ) { if ( this . ranges . length <= 0 ) return { begin : 0 , end : 0 } ; let begin = Math . max ( 0 , this . indexAt ( range . start ) ) ; if ( this . ranges [ begin ] . end . isBefore ( range . start ) ) ++ begin ; else if ( ! options . includeTouchingStart && this . ranges [ begin ] . end . isEqual ( range . start ) ) ++ begin ; let end = Math . max ( begin , this . indexAt ( range . end , begin ) ) ; if ( end < this . ranges . length && this . ranges [ end ] . end . isAfter ( range . start ) && this . ranges [ end ] . start . isBefore ( range . end ) ) ++ end ; else if ( end < this . ranges . length && options . includeTouchingEnd && this . ranges [ end ] . start . isEqual ( range . end ) ) ++ end ; else if ( end < this . ranges . length && options . includeTouchingStart && this . ranges [ end ] . end . isEqual ( range . start ) ) ++ end ; return { begin : begin , end : end } ; } /** Calculate the set of ranges that overlap `range` */ public getOverlapping ( range , options ) { const { begin : begin , end : end } = this . getOverlappingIndices ( range , options ) ; return this . ranges . slice ( begin , end ) ; } /** Removes all ranges that intersect with `range`, returning the removed elements */ public removeOverlapping ( range , options ) { const { begin : begin , end : end } = this . getOverlappingIndices ( range , options ) ; return this . ranges . splice ( begin , end - begin ) ; } public add ( range ) { if ( range . isEmpty ) return ; if ( this . ranges . length == 0 ) { this . ranges . push ( range ) ; return ; } const beginPos = this . ranges . findIndex ( ( r ) => r . end . isAfterOrEqual ( range . start ) ) ; if ( beginPos == - 1 ) { this . ranges . push ( range ) ; return ; } const r0 = this . ranges [ beginPos ] ; if ( r0 . start . isAfter ( range . end ) ) { this . ranges . splice ( beginPos , 0 , range ) ; return ; } let endPos = this . ranges . findIndex ( ( r ) => r . start . isAfter ( range . end ) ) ; if ( endPos == - 1 ) endPos = this . ranges . length ; const r1 = this . ranges [ endPos - 1 ] ; this . ranges [ beginPos ] = r0 . union ( r1 . union ( range ) ) ; this . ranges . splice ( beginPos + 1 , endPos - beginPos - 1 ) ; } public subtract ( range ) { if ( this . ranges . length == 0 || this . ranges [ 0 ] . isEmpty || range . isEmpty ) { return ; } const beginPos = this . ranges . findIndex ( ( r ) => r . end . isAfter ( range . start ) ) ; if ( beginPos == - 1 ) return ; const r0a = this . ranges [ beginPos ] . start ; let remainder1 ; if ( r0a . isAfterOrEqual ( range . end ) ) return ; else if ( r0a . isAfterOrEqual ( range . start ) ) remainder1 = new vscode . Range ( r0a , r0a ) ; else remainder1 = new vscode . Range ( r0a , range . start ) ; let endPos = this . ranges . findIndex ( ( r ) => r . end . isAfter ( range . end ) ) ; let remainder2 ; if ( endPos == - 1 ) { endPos = this . ranges . length ; remainder2 = new vscode . Range ( r0a , r0a ) ; } else if ( this . ranges [ endPos ] . start . isAfterOrEqual ( range . end ) ) remainder2 = new vscode . Range ( r0a , r0a ) ; else { remainder2 = new vscode . Range ( range . end , this . ranges [ endPos ] . end ) ; ++ endPos ; } if ( remainder1 . isEmpty ) { if ( remainder2 . isEmpty ) this . ranges . splice ( beginPos , endPos - beginPos ) ; else { this . ranges . splice ( beginPos , endPos - beginPos , remainder2 ) ; } } else if ( remainder2 . isEmpty ) this . ranges . splice ( beginPos , endPos - beginPos , remainder1 ) ; else this . ranges . splice ( beginPos , endPos - beginPos , remainder1 , remainder2 ) ; } public applyEdit ( delta ) { for ( let idx = 0 ; idx < this . ranges . length ; ++ idx ) this . ranges [ idx ] = textUtil . rangeTranslate ( this . ranges [ idx ] , delta ) ; } public toString ( ) { return this . ranges . toString ( ) ; } returns private indexAt ( position , begin ? , end ? ) { if ( ! begin ) begin = 0 ; if ( ! end ) end = this . ranges . length ; while ( begin < end ) { const pivot = ( begin + end ) >> 1 ; const pivotRange = this . ranges [ pivot ] ; if ( position . isBefore ( pivotRange . start ) ) end = pivot ; else if ( position . isBefore ( pivotRange . end ) ) return pivot ; else if ( begin == pivot ) break ; else begin = pivot ; } return begin ; } public getRanges ( ) { return this . ranges ; } }