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