UNPKG

vscode-todo-plus

Version:

Manage todo lists with ease. Powerful, easy to use and customizable.

135 lines (82 loc) 3.4 kB
/* IMPORT */ import * as _ from 'lodash'; import stringMatches from 'string-matches'; import * as vscode from 'vscode'; import Utils from '../../utils'; import LineItem from '../items/line'; /* LINE */ class Line { TYPES = []; /* RANGE */ parseRanges ( text: string, rangesRaw: vscode.Range | RegExp | vscode.Range[] | RegExp[] ) { let negRanges = _.flatten ( _.castArray ( rangesRaw as any ) ); //TSC 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: string, posRange: vscode.Range, negRangesRaw: vscode.Range | RegExp | vscode.Range[] | RegExp[] = [] ) { const posOffset = posRange.start.character; /* NEGATIVE RANGES */ const negRanges = this.parseRanges ( text, negRangesRaw ).filter ( range => range && range.start < range.end && ( !range['line'] || range['line'] === posRange.start.line ) ); //TSC /* DIFFERENCE */ if ( !negRanges.length ) return [posRange]; // Algorithm: // 1. All cells start unfilled // 2. Filling all the positive cells // 3. Unfilling all the negative cells // 4. Transforming consecutive positive cells to ranges const cells = Array ( posOffset + text.length ); // 1. _.fill ( cells, true, posRange.start.character, posRange.end.character ); // 2. negRanges.forEach ( ({ start, end }) => _.fill ( cells, false, posOffset + start, posOffset + end ) ); // 3. const ranges: vscode.Range[] = []; let start = null, end = null; for ( let i = 0, l = cells.length; i < l; i++ ) { // 4. const cell = cells[i]; if ( start === null ) { if ( cell ) start = i; } else { if ( !cell ) end = i; } if ( start !== null && ( end !== null || i === l - 1 ) ) { //FIXME: What if there's only 1 character? end = end !== null ? end : l; ranges.push ( new vscode.Range ( posRange.start.line, start, posRange.start.line, end ) ); start = null; end = null; } } return ranges; } /* ITEMS */ getItemRanges ( item: LineItem, negRanges?: vscode.Range | vscode.Range[] | RegExp | RegExp[] ) { return _.isEmpty ( negRanges ) ? [item.range] : [this.getRangeDifference ( item.text, item.range, negRanges )]; } getItemsRanges ( items: LineItem[], negRanges?: vscode.Range | vscode.Range[] | RegExp | RegExp[] ) { const ranges = items.map ( item => this.getItemRanges ( item, negRanges ) ), zipped = _.zip ( ...ranges as any ), //TSC compact = zipped.map ( _.compact ), concat = compact.map ( r => _.concat ( [], ...r ) ); return concat; } getDecorations ( items: LineItem[], negRanges?: vscode.Range | vscode.Range[] | RegExp | RegExp[] ) { let ranges = this.getItemsRanges ( items, negRanges ); return this.TYPES.map ( ( type, index ) => ({ type, ranges: ranges[index] || [] })); } } /* EXPORT */ export default Line;