export interface TextRange { start : number ; length : number ; } export namespace TextRange { export function create ( start , length ) { if ( start < 0 ) { throw new Error ( 'start must be non-negative' ) ; } if ( length < 0 ) { throw new Error ( 'length must be non-negative' ) ; } return { start , length } ; } export function fromBounds ( start , end ) { if ( start < 0 ) { throw new Error ( 'start must be non-negative' ) ; } if ( start > end ) { throw new Error ( 'end must be greater than or equal to start' ) ; } return create ( start , end - start ) ; } export function getEnd ( range ) { return range . start + range . length ; } export function contains ( range , position ) { return position >= range . start && position < getEnd ( range ) ; } export function containsRange ( range , span ) { return span . start >= range . start && getEnd ( span ) <= getEnd ( range ) ; } export function overlaps ( range , position ) { return position >= range . start && position <= getEnd ( range ) ; } export function overlapsRange ( range , other ) { return overlaps ( range , other . start ) || overlaps ( other , range . start ) ; } export function extend ( range , extension ) { if ( extension ) { if ( Array . isArray ( extension ) ) { extension . forEach ( ( r ) => { extend ( range , r ) ; } ) ; } else { if ( extension . start < range . start ) { range . length += range . start - extension . start ; range . start = extension . start ; } if ( getEnd ( extension ) > getEnd ( range ) ) { range . length += getEnd ( extension ) - getEnd ( range ) ; } } } } export function combine ( ranges ) { if ( ranges . length === 0 ) { return undefined ; } const combinedRange = ranges [ 0 ] ; for ( let i = 1 ; i < ranges . length ; i ++ ) { extend ( combinedRange , ranges [ i ] ) ; } return combinedRange ; } } export interface Position { line : number ; character : number ; } export namespace Position { export function is ( value ) { const candidate = value as Position ; return candidate && candidate . line !== void 0 && candidate . character !== void 0 ; } export function print ( value ) { return `(${ value . line }:${ value . character })` ; } } export interface Range { start : Position ; end : Position ; } export namespace Range { export function is ( value ) { const candidate = value as Range ; return candidate && candidate . start !== void 0 && candidate . end !== void 0 ; } export function print ( value ) { return `${ Position . print ( value . start ) }-${ Position . print ( value . end ) }` ; } } export interface DocumentRange { path : string ; range : Range ; } export function comparePositions ( a , b ) { if ( a . line < b . line ) { return - 1 ; } else if ( a . line > b . line ) { return 1 ; } else if ( a . character < b . character ) { return - 1 ; } else if ( a . character > b . character ) { return 1 ; } return 0 ; } export function getEmptyPosition ( ) { return { line : 0 , character : 0 , } ; } export function doRangesOverlap ( a , b ) { if ( comparePositions ( b . start , a . end ) >= 0 ) { return false ; } else if ( comparePositions ( a . start , b . end ) >= 0 ) { return false ; } return true ; } export function doRangesIntersect ( a , b ) { if ( comparePositions ( b . start , a . end ) > 0 ) { return false ; } else if ( comparePositions ( a . start , b . end ) > 0 ) { return false ; } return true ; } export function doesRangeContain ( range , positionOrRange ) { if ( Position . is ( positionOrRange ) ) { return comparePositions ( range . start , positionOrRange ) <= 0 && comparePositions ( range . end , positionOrRange ) >= 0 ; } return doesRangeContain ( range , positionOrRange . start ) && doesRangeContain ( range , positionOrRange . end ) ; } export function positionsAreEqual ( a , b ) { return comparePositions ( a , b ) === 0 ; } export function rangesAreEqual ( a , b ) { return positionsAreEqual ( a . start , b . start ) && positionsAreEqual ( a . end , b . end ) ; } export function getEmptyRange ( ) { return { start : getEmptyPosition ( ) , end : getEmptyPosition ( ) , } ; } export function isEmptyPosition ( pos ) { return pos . character === 0 && pos . line === 0 ; } export function isEmptyRange ( range ) { return isEmptyPosition ( range . start ) && isEmptyPosition ( range . end ) ; } export function extendRange ( range , extension ) { if ( extension ) { if ( Array . isArray ( extension ) ) { extension . forEach ( ( r ) => { extendRange ( range , r ) ; } ) ; } else { if ( comparePositions ( extension . start , range . start ) < 0 ) { range . start = extension . start ; } if ( comparePositions ( extension . end , range . end ) > 0 ) { range . end = extension . end ; } } } } export function combineRange ( ranges ) { if ( ranges . length === 0 ) { return undefined ; } const combinedRange = ranges [ 0 ] ; for ( let i = 1 ; i < ranges . length ; i ++ ) { extendRange ( combinedRange , ranges [ i ] ) ; } return combinedRange ; }