import * as _ from 'lodash' ; import stringMatches from 'string-matches' ; import * as vscode from 'vscode' ; import Utils from '../../utils' ; import LineItem from '../items/line' ; class Line { TYPES = [ ] ; parseRanges ( text , rangesRaw ) { let negRanges = _ . flatten ( _ . castArray ( rangesRaw as any ) ) ; return _ . filter ( _ . flatten ( negRanges . map ( neg => { if ( ! neg ) return ; if ( neg instanceof vscode . Range ) { return { start : neg . start . character , startLine : neg . start . line , end : neg . end . character , endLine : neg . end . line } ; } else if ( neg instanceof RegExp ) { const matches = stringMatches ( text , neg ) , ranges = Utils . regex . matches2ranges ( matches ) ; return ranges ; } } ) ) ) ; } getRangeDifference ( text , posRange , negRangesRaw = [ ] ) { const posOffset = posRange . start . character ; const negRanges = this . parseRanges ( text , negRangesRaw ) . filter ( range => range && range . start < range . end && ( ! range [ 'line' ] || range [ 'line' ] === posRange . start . line ) ) ; if ( ! negRanges . length ) return [ posRange ] ; const cells = Array ( posOffset + text . length ) ; _ . fill ( cells , true , posRange . start . character , posRange . end . character ) ; negRanges . forEach ( ( { start , end } ) => _ . fill ( cells , false , posOffset + start , posOffset + end ) ) ; const ranges = [ ] ; let start = null , end = null ; for ( let i = 0 , l = cells . length ; i < l ; i ++ ) { const cell = cells [ i ] ; if ( start === null ) { if ( cell ) start = i ; } else { if ( ! cell ) end = i ; } if ( start !== null && ( end !== null || i === l - 1 ) ) { end = end !== null ? end : l ; ranges . push ( new vscode . Range ( posRange . start . line , start , posRange . start . line , end ) ) ; start = null ; end = null ; } } return ranges ; } getItemRanges ( item , negRanges ? ) { return _ . isEmpty ( negRanges ) ? [ item . range ] : [ this . getRangeDifference ( item . text , item . range , negRanges ) ] ; } getItemsRanges ( items , negRanges ? ) { const ranges = items . map ( item => this . getItemRanges ( item , negRanges ) ) , zipped = _ . zip ( ... ranges as any ) , compact = zipped . map ( _ . compact ) , concat = compact . map ( r => _ . concat ( [ ] , ... r ) ) ; return concat ; } getDecorations ( items , negRanges ? ) { let ranges = this . getItemsRanges ( items , negRanges ) ; return this . TYPES . map ( ( type , index ) => ( { type , ranges : ranges [ index ] || [ ] } ) ) ; } } export default Line ;