| const FOLD_FLOW = 'flow'; | |
| const FOLD_BLOCK = 'block'; | |
| const FOLD_QUOTED = 'quoted'; | |
| /** | |
| * Tries to keep input at up to `lineWidth` characters, splitting only on spaces | |
| * not followed by newlines or spaces unless `mode` is `'quoted'`. Lines are | |
| * terminated with `\n` and started with `indent`. | |
| */ | |
| function foldFlowLines(text, indent, mode = 'flow', { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) { | |
| if (!lineWidth || lineWidth < 0) | |
| return text; | |
| if (lineWidth < minContentWidth) | |
| minContentWidth = 0; | |
| const endStep = Math.max(1 + minContentWidth, 1 + lineWidth - indent.length); | |
| if (text.length <= endStep) | |
| return text; | |
| const folds = []; | |
| const escapedFolds = {}; | |
| let end = lineWidth - indent.length; | |
| if (typeof indentAtStart === 'number') { | |
| if (indentAtStart > lineWidth - Math.max(2, minContentWidth)) | |
| folds.push(0); | |
| else | |
| end = lineWidth - indentAtStart; | |
| } | |
| let split = undefined; | |
| let prev = undefined; | |
| let overflow = false; | |
| let i = -1; | |
| let escStart = -1; | |
| let escEnd = -1; | |
| if (mode === FOLD_BLOCK) { | |
| i = consumeMoreIndentedLines(text, i, indent.length); | |
| if (i !== -1) | |
| end = i + endStep; | |
| } | |
| for (let ch; (ch = text[(i += 1)]);) { | |
| if (mode === FOLD_QUOTED && ch === '\\') { | |
| escStart = i; | |
| switch (text[i + 1]) { | |
| case 'x': | |
| i += 3; | |
| break; | |
| case 'u': | |
| i += 5; | |
| break; | |
| case 'U': | |
| i += 9; | |
| break; | |
| default: | |
| i += 1; | |
| } | |
| escEnd = i; | |
| } | |
| if (ch === '\n') { | |
| if (mode === FOLD_BLOCK) | |
| i = consumeMoreIndentedLines(text, i, indent.length); | |
| end = i + indent.length + endStep; | |
| split = undefined; | |
| } | |
| else { | |
| if (ch === ' ' && | |
| prev && | |
| prev !== ' ' && | |
| prev !== '\n' && | |
| prev !== '\t') { | |
| // space surrounded by non-space can be replaced with newline + indent | |
| const next = text[i + 1]; | |
| if (next && next !== ' ' && next !== '\n' && next !== '\t') | |
| split = i; | |
| } | |
| if (i >= end) { | |
| if (split) { | |
| folds.push(split); | |
| end = split + endStep; | |
| split = undefined; | |
| } | |
| else if (mode === FOLD_QUOTED) { | |
| // white-space collected at end may stretch past lineWidth | |
| while (prev === ' ' || prev === '\t') { | |
| prev = ch; | |
| ch = text[(i += 1)]; | |
| overflow = true; | |
| } | |
| // Account for newline escape, but don't break preceding escape | |
| const j = i > escEnd + 1 ? i - 2 : escStart - 1; | |
| // Bail out if lineWidth & minContentWidth are shorter than an escape string | |
| if (escapedFolds[j]) | |
| return text; | |
| folds.push(j); | |
| escapedFolds[j] = true; | |
| end = j + endStep; | |
| split = undefined; | |
| } | |
| else { | |
| overflow = true; | |
| } | |
| } | |
| } | |
| prev = ch; | |
| } | |
| if (overflow && onOverflow) | |
| onOverflow(); | |
| if (folds.length === 0) | |
| return text; | |
| if (onFold) | |
| onFold(); | |
| let res = text.slice(0, folds[0]); | |
| for (let i = 0; i < folds.length; ++i) { | |
| const fold = folds[i]; | |
| const end = folds[i + 1] || text.length; | |
| if (fold === 0) | |
| res = `\n${indent}${text.slice(0, end)}`; | |
| else { | |
| if (mode === FOLD_QUOTED && escapedFolds[fold]) | |
| res += `${text[fold]}\\`; | |
| res += `\n${indent}${text.slice(fold + 1, end)}`; | |
| } | |
| } | |
| return res; | |
| } | |
| /** | |
| * Presumes `i + 1` is at the start of a line | |
| * @returns index of last newline in more-indented block | |
| */ | |
| function consumeMoreIndentedLines(text, i, indent) { | |
| let end = i; | |
| let start = i + 1; | |
| let ch = text[start]; | |
| while (ch === ' ' || ch === '\t') { | |
| if (i < start + indent) { | |
| ch = text[++i]; | |
| } | |
| else { | |
| do { | |
| ch = text[++i]; | |
| } while (ch && ch !== '\n'); | |
| end = i; | |
| start = i + 1; | |
| ch = text[start]; | |
| } | |
| } | |
| return end; | |
| } | |
| export { FOLD_BLOCK, FOLD_FLOW, FOLD_QUOTED, foldFlowLines }; | |
Xet Storage Details
- Size:
- 4.79 kB
- Xet hash:
- d8855bc494297984201280d126046415ce056e99c9c753315b8acfe9c97b927e
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.