1 | 'use strict';
|
2 |
|
3 | const FOLD_FLOW = 'flow';
|
4 | const FOLD_BLOCK = 'block';
|
5 | const FOLD_QUOTED = 'quoted';
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | function foldFlowLines(text, indent, mode = 'flow', { indentAtStart, lineWidth = 80, minContentWidth = 20, onFold, onOverflow } = {}) {
|
12 | if (!lineWidth || lineWidth < 0)
|
13 | return text;
|
14 | const endStep = Math.max(1 + minContentWidth, 1 + lineWidth - indent.length);
|
15 | if (text.length <= endStep)
|
16 | return text;
|
17 | const folds = [];
|
18 | const escapedFolds = {};
|
19 | let end = lineWidth - indent.length;
|
20 | if (typeof indentAtStart === 'number') {
|
21 | if (indentAtStart > lineWidth - Math.max(2, minContentWidth))
|
22 | folds.push(0);
|
23 | else
|
24 | end = lineWidth - indentAtStart;
|
25 | }
|
26 | let split = undefined;
|
27 | let prev = undefined;
|
28 | let overflow = false;
|
29 | let i = -1;
|
30 | let escStart = -1;
|
31 | let escEnd = -1;
|
32 | if (mode === FOLD_BLOCK) {
|
33 | i = consumeMoreIndentedLines(text, i, indent.length);
|
34 | if (i !== -1)
|
35 | end = i + endStep;
|
36 | }
|
37 | for (let ch; (ch = text[(i += 1)]);) {
|
38 | if (mode === FOLD_QUOTED && ch === '\\') {
|
39 | escStart = i;
|
40 | switch (text[i + 1]) {
|
41 | case 'x':
|
42 | i += 3;
|
43 | break;
|
44 | case 'u':
|
45 | i += 5;
|
46 | break;
|
47 | case 'U':
|
48 | i += 9;
|
49 | break;
|
50 | default:
|
51 | i += 1;
|
52 | }
|
53 | escEnd = i;
|
54 | }
|
55 | if (ch === '\n') {
|
56 | if (mode === FOLD_BLOCK)
|
57 | i = consumeMoreIndentedLines(text, i, indent.length);
|
58 | end = i + indent.length + endStep;
|
59 | split = undefined;
|
60 | }
|
61 | else {
|
62 | if (ch === ' ' &&
|
63 | prev &&
|
64 | prev !== ' ' &&
|
65 | prev !== '\n' &&
|
66 | prev !== '\t') {
|
67 |
|
68 | const next = text[i + 1];
|
69 | if (next && next !== ' ' && next !== '\n' && next !== '\t')
|
70 | split = i;
|
71 | }
|
72 | if (i >= end) {
|
73 | if (split) {
|
74 | folds.push(split);
|
75 | end = split + endStep;
|
76 | split = undefined;
|
77 | }
|
78 | else if (mode === FOLD_QUOTED) {
|
79 |
|
80 | while (prev === ' ' || prev === '\t') {
|
81 | prev = ch;
|
82 | ch = text[(i += 1)];
|
83 | overflow = true;
|
84 | }
|
85 |
|
86 | const j = i > escEnd + 1 ? i - 2 : escStart - 1;
|
87 |
|
88 | if (escapedFolds[j])
|
89 | return text;
|
90 | folds.push(j);
|
91 | escapedFolds[j] = true;
|
92 | end = j + endStep;
|
93 | split = undefined;
|
94 | }
|
95 | else {
|
96 | overflow = true;
|
97 | }
|
98 | }
|
99 | }
|
100 | prev = ch;
|
101 | }
|
102 | if (overflow && onOverflow)
|
103 | onOverflow();
|
104 | if (folds.length === 0)
|
105 | return text;
|
106 | if (onFold)
|
107 | onFold();
|
108 | let res = text.slice(0, folds[0]);
|
109 | for (let i = 0; i < folds.length; ++i) {
|
110 | const fold = folds[i];
|
111 | const end = folds[i + 1] || text.length;
|
112 | if (fold === 0)
|
113 | res = `\n${indent}${text.slice(0, end)}`;
|
114 | else {
|
115 | if (mode === FOLD_QUOTED && escapedFolds[fold])
|
116 | res += `${text[fold]}\\`;
|
117 | res += `\n${indent}${text.slice(fold + 1, end)}`;
|
118 | }
|
119 | }
|
120 | return res;
|
121 | }
|
122 |
|
123 |
|
124 |
|
125 |
|
126 | function consumeMoreIndentedLines(text, i, indent) {
|
127 | let end = i;
|
128 | let start = i + 1;
|
129 | let ch = text[start];
|
130 | while (ch === ' ' || ch === '\t') {
|
131 | if (i < start + indent) {
|
132 | ch = text[++i];
|
133 | }
|
134 | else {
|
135 | do {
|
136 | ch = text[++i];
|
137 | } while (ch && ch !== '\n');
|
138 | end = i;
|
139 | start = i + 1;
|
140 | ch = text[start];
|
141 | }
|
142 | }
|
143 | return end;
|
144 | }
|
145 |
|
146 | exports.FOLD_BLOCK = FOLD_BLOCK;
|
147 | exports.FOLD_FLOW = FOLD_FLOW;
|
148 | exports.FOLD_QUOTED = FOLD_QUOTED;
|
149 | exports.foldFlowLines = foldFlowLines;
|