Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 161x 161x 56x 284x 284x 56x 56x 56x 116x 116x 56x 283x 127x 127x 127x 127x 127x 56x 56x 56x 71x 37x 9x 9x 37x 56x 56x | const range: number = 2 export function generateCodeFrame( source: string, start = 0, end = source.length ): string { // Split the content into individual lines but capture the newline sequence // that separated each line. This is important because the actual sequence is // needed to properly take into account the full line length for offset // comparison let lines = source.split(/(\r?\n)/) // Separate the lines and newline sequences into separate arrays for easier referencing const newlineSequences = lines.filter((_, idx) => idx % 2 === 1) lines = lines.filter((_, idx) => idx % 2 === 0) let count = 0 const res: string[] = [] for (let i = 0; i < lines.length; i++) { count += lines[i].length + ((newlineSequences[i] && newlineSequences[i].length) || 0) if (count >= start) { for (let j = i - range; j <= i + range || end > count; j++) { if (j < 0 || j >= lines.length) continue const line = j + 1 res.push( `${line}${' '.repeat(Math.max(3 - String(line).length, 0))}| ${ lines[j] }` ) const lineLength = lines[j].length const newLineSeqLength = (newlineSequences[j] && newlineSequences[j].length) || 0 if (j === i) { // push underline const pad = start - (count - (lineLength + newLineSeqLength)) const length = Math.max( 1, end > count ? lineLength - pad : end - start ) res.push(` | ` + ' '.repeat(pad) + '^'.repeat(length)) } else if (j > i) { if (end > count) { const length = Math.max(Math.min(end - count, lineLength), 1) res.push(` | ` + '^'.repeat(length)) } count += lineLength + newLineSeqLength } } break } } return res.join('\n') } |