wrap-ansi 3.0.1 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +81 -89
- package/package.json +59 -60
- package/readme.md +13 -5
package/index.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
'use strict';
|
2
2
|
const stringWidth = require('string-width');
|
3
3
|
const stripAnsi = require('strip-ansi');
|
4
|
+
const ansiStyles = require('ansi-styles');
|
4
5
|
|
5
6
|
const ESCAPES = new Set([
|
6
7
|
'\u001B',
|
@@ -9,74 +10,44 @@ const ESCAPES = new Set([
|
|
9
10
|
|
10
11
|
const END_CODE = 39;
|
11
12
|
|
12
|
-
const ESCAPE_CODES = new Map([
|
13
|
-
[0, 0],
|
14
|
-
[1, 22],
|
15
|
-
[2, 22],
|
16
|
-
[3, 23],
|
17
|
-
[4, 24],
|
18
|
-
[7, 27],
|
19
|
-
[8, 28],
|
20
|
-
[9, 29],
|
21
|
-
[30, 39],
|
22
|
-
[31, 39],
|
23
|
-
[32, 39],
|
24
|
-
[33, 39],
|
25
|
-
[34, 39],
|
26
|
-
[35, 39],
|
27
|
-
[36, 39],
|
28
|
-
[37, 39],
|
29
|
-
[90, 39],
|
30
|
-
[40, 49],
|
31
|
-
[41, 49],
|
32
|
-
[42, 49],
|
33
|
-
[43, 49],
|
34
|
-
[44, 49],
|
35
|
-
[45, 49],
|
36
|
-
[46, 49],
|
37
|
-
[47, 49]
|
38
|
-
]);
|
39
|
-
|
40
13
|
const wrapAnsi = code => `${ESCAPES.values().next().value}[${code}m`;
|
41
14
|
|
42
15
|
// Calculate the length of words split on ' ', ignoring
|
43
16
|
// the extra characters added by ansi escape codes
|
44
|
-
const wordLengths =
|
17
|
+
const wordLengths = string => string.split(' ').map(character => stringWidth(character));
|
45
18
|
|
46
19
|
// Wrap a long word across multiple rows
|
47
20
|
// Ansi escape codes do not count towards length
|
48
|
-
const wrapWord = (rows, word,
|
49
|
-
const
|
21
|
+
const wrapWord = (rows, word, columns) => {
|
22
|
+
const characters = [...word];
|
50
23
|
|
51
|
-
let
|
24
|
+
let isInsideEscape = false;
|
52
25
|
let visible = stringWidth(stripAnsi(rows[rows.length - 1]));
|
53
26
|
|
54
|
-
for (const
|
55
|
-
const
|
56
|
-
const char = item[1];
|
57
|
-
const charLength = stringWidth(char);
|
27
|
+
for (const [index, character] of characters.entries()) {
|
28
|
+
const characterLength = stringWidth(character);
|
58
29
|
|
59
|
-
if (visible +
|
60
|
-
rows[rows.length - 1] +=
|
30
|
+
if (visible + characterLength <= columns) {
|
31
|
+
rows[rows.length - 1] += character;
|
61
32
|
} else {
|
62
|
-
rows.push(
|
33
|
+
rows.push(character);
|
63
34
|
visible = 0;
|
64
35
|
}
|
65
36
|
|
66
|
-
if (ESCAPES.has(
|
67
|
-
|
68
|
-
} else if (
|
69
|
-
|
37
|
+
if (ESCAPES.has(character)) {
|
38
|
+
isInsideEscape = true;
|
39
|
+
} else if (isInsideEscape && character === 'm') {
|
40
|
+
isInsideEscape = false;
|
70
41
|
continue;
|
71
42
|
}
|
72
43
|
|
73
|
-
if (
|
44
|
+
if (isInsideEscape) {
|
74
45
|
continue;
|
75
46
|
}
|
76
47
|
|
77
|
-
visible +=
|
48
|
+
visible += characterLength;
|
78
49
|
|
79
|
-
if (visible ===
|
50
|
+
if (visible === columns && index < characters.length - 1) {
|
80
51
|
rows.push('');
|
81
52
|
visible = 0;
|
82
53
|
}
|
@@ -89,92 +60,113 @@ const wrapWord = (rows, word, cols) => {
|
|
89
60
|
}
|
90
61
|
};
|
91
62
|
|
92
|
-
//
|
93
|
-
|
63
|
+
// Trims spaces from a string ignoring invisible sequences
|
64
|
+
const stringVisibleTrimSpacesRight = str => {
|
65
|
+
const words = str.split(' ');
|
66
|
+
let last = words.length;
|
67
|
+
|
68
|
+
while (last > 0) {
|
69
|
+
if (stringWidth(words[last - 1]) > 0) {
|
70
|
+
break;
|
71
|
+
}
|
72
|
+
|
73
|
+
last--;
|
74
|
+
}
|
75
|
+
|
76
|
+
if (last === words.length) {
|
77
|
+
return str;
|
78
|
+
}
|
79
|
+
|
80
|
+
return words.slice(0, last).join(' ') + words.slice(last).join('');
|
81
|
+
};
|
82
|
+
|
83
|
+
// The wrap-ansi module can be invoked in either 'hard' or 'soft' wrap mode
|
94
84
|
//
|
95
|
-
// 'hard' will never allow a string to take up more
|
96
|
-
// than cols characters
|
85
|
+
// 'hard' will never allow a string to take up more than columns characters
|
97
86
|
//
|
98
87
|
// 'soft' allows long words to expand past the column length
|
99
|
-
const exec = (
|
100
|
-
|
101
|
-
|
102
|
-
if (str.trim() === '') {
|
103
|
-
return options.trim === false ? str : str.trim();
|
88
|
+
const exec = (string, columns, options = {}) => {
|
89
|
+
if (options.trim !== false && string.trim() === '') {
|
90
|
+
return '';
|
104
91
|
}
|
105
92
|
|
106
93
|
let pre = '';
|
107
94
|
let ret = '';
|
108
95
|
let escapeCode;
|
109
96
|
|
110
|
-
const lengths = wordLengths(
|
111
|
-
|
112
|
-
const rows = [''];
|
97
|
+
const lengths = wordLengths(string);
|
98
|
+
let rows = [''];
|
113
99
|
|
114
|
-
for (const
|
115
|
-
|
116
|
-
|
100
|
+
for (const [index, word] of string.split(' ').entries()) {
|
101
|
+
if (options.trim !== false) {
|
102
|
+
rows[rows.length - 1] = rows[rows.length - 1].trimLeft();
|
103
|
+
}
|
117
104
|
|
118
|
-
rows[rows.length - 1] = options.trim === false ? rows[rows.length - 1] : rows[rows.length - 1].trim();
|
119
105
|
let rowLength = stringWidth(rows[rows.length - 1]);
|
120
106
|
|
121
|
-
if (
|
122
|
-
if (rowLength
|
107
|
+
if (index !== 0) {
|
108
|
+
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
|
123
109
|
// If we start with a new word but the current row length equals the length of the columns, add a new row
|
124
110
|
rows.push('');
|
125
111
|
rowLength = 0;
|
126
112
|
}
|
127
113
|
|
128
|
-
|
129
|
-
|
114
|
+
if (rowLength > 0 || options.trim === false) {
|
115
|
+
rows[rows.length - 1] += ' ';
|
116
|
+
rowLength++;
|
117
|
+
}
|
130
118
|
}
|
131
119
|
|
132
|
-
// In 'hard' wrap mode, the length of a line is
|
133
|
-
|
134
|
-
|
135
|
-
|
120
|
+
// In 'hard' wrap mode, the length of a line is never allowed to extend past 'columns'
|
121
|
+
if (options.hard && lengths[index] > columns) {
|
122
|
+
const remainingColumns = (columns - rowLength);
|
123
|
+
const breaksStartingThisLine = 1 + Math.floor((lengths[index] - remainingColumns - 1) / columns);
|
124
|
+
const breaksStartingNextLine = Math.floor((lengths[index] - 1) / columns);
|
125
|
+
if (breaksStartingNextLine < breaksStartingThisLine) {
|
136
126
|
rows.push('');
|
137
127
|
}
|
138
|
-
|
128
|
+
|
129
|
+
wrapWord(rows, word, columns);
|
139
130
|
continue;
|
140
131
|
}
|
141
132
|
|
142
|
-
if (rowLength + lengths[
|
143
|
-
if (options.wordWrap === false && rowLength <
|
144
|
-
wrapWord(rows, word,
|
133
|
+
if (rowLength + lengths[index] > columns && rowLength > 0 && lengths[index] > 0) {
|
134
|
+
if (options.wordWrap === false && rowLength < columns) {
|
135
|
+
wrapWord(rows, word, columns);
|
145
136
|
continue;
|
146
137
|
}
|
147
138
|
|
148
139
|
rows.push('');
|
149
140
|
}
|
150
141
|
|
151
|
-
if (rowLength + lengths[
|
152
|
-
wrapWord(rows, word,
|
142
|
+
if (rowLength + lengths[index] > columns && options.wordWrap === false) {
|
143
|
+
wrapWord(rows, word, columns);
|
153
144
|
continue;
|
154
145
|
}
|
155
146
|
|
156
147
|
rows[rows.length - 1] += word;
|
157
148
|
}
|
158
149
|
|
159
|
-
|
150
|
+
if (options.trim !== false) {
|
151
|
+
rows = rows.map(stringVisibleTrimSpacesRight);
|
152
|
+
}
|
160
153
|
|
161
|
-
|
162
|
-
const i = item[0];
|
163
|
-
const char = item[1];
|
154
|
+
pre = rows.join('\n');
|
164
155
|
|
165
|
-
|
156
|
+
for (const [index, character] of [...pre].entries()) {
|
157
|
+
ret += character;
|
166
158
|
|
167
|
-
if (ESCAPES.has(
|
168
|
-
const code = parseFloat(/\d[^m]*/.exec(pre.slice(
|
159
|
+
if (ESCAPES.has(character)) {
|
160
|
+
const code = parseFloat(/\d[^m]*/.exec(pre.slice(index, index + 4)));
|
169
161
|
escapeCode = code === END_CODE ? null : code;
|
170
162
|
}
|
171
163
|
|
172
|
-
const code =
|
164
|
+
const code = ansiStyles.codes.get(Number(escapeCode));
|
173
165
|
|
174
166
|
if (escapeCode && code) {
|
175
|
-
if (pre[
|
167
|
+
if (pre[index + 1] === '\n') {
|
176
168
|
ret += wrapAnsi(code);
|
177
|
-
} else if (
|
169
|
+
} else if (character === '\n') {
|
178
170
|
ret += wrapAnsi(escapeCode);
|
179
171
|
}
|
180
172
|
}
|
@@ -184,10 +176,10 @@ const exec = (str, cols, opts) => {
|
|
184
176
|
};
|
185
177
|
|
186
178
|
// For each newline, invoke the method separately
|
187
|
-
module.exports = (
|
188
|
-
return String(
|
179
|
+
module.exports = (string, columns, options) => {
|
180
|
+
return String(string)
|
189
181
|
.normalize()
|
190
182
|
.split('\n')
|
191
|
-
.map(line => exec(line,
|
183
|
+
.map(line => exec(line, columns, options))
|
192
184
|
.join('\n');
|
193
185
|
};
|
package/package.json
CHANGED
@@ -1,62 +1,61 @@
|
|
1
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
|
-
|
60
|
-
|
61
|
-
}
|
2
|
+
"name": "wrap-ansi",
|
3
|
+
"version": "6.0.0",
|
4
|
+
"description": "Wordwrap a string with ANSI escape codes",
|
5
|
+
"license": "MIT",
|
6
|
+
"repository": "chalk/wrap-ansi",
|
7
|
+
"author": {
|
8
|
+
"name": "Sindre Sorhus",
|
9
|
+
"email": "sindresorhus@gmail.com",
|
10
|
+
"url": "sindresorhus.com"
|
11
|
+
},
|
12
|
+
"engines": {
|
13
|
+
"node": ">=8"
|
14
|
+
},
|
15
|
+
"scripts": {
|
16
|
+
"test": "xo && nyc ava"
|
17
|
+
},
|
18
|
+
"files": [
|
19
|
+
"index.js"
|
20
|
+
],
|
21
|
+
"keywords": [
|
22
|
+
"wrap",
|
23
|
+
"break",
|
24
|
+
"wordwrap",
|
25
|
+
"wordbreak",
|
26
|
+
"linewrap",
|
27
|
+
"ansi",
|
28
|
+
"styles",
|
29
|
+
"color",
|
30
|
+
"colour",
|
31
|
+
"colors",
|
32
|
+
"terminal",
|
33
|
+
"console",
|
34
|
+
"cli",
|
35
|
+
"string",
|
36
|
+
"tty",
|
37
|
+
"escape",
|
38
|
+
"formatting",
|
39
|
+
"rgb",
|
40
|
+
"256",
|
41
|
+
"shell",
|
42
|
+
"xterm",
|
43
|
+
"log",
|
44
|
+
"logging",
|
45
|
+
"command-line",
|
46
|
+
"text"
|
47
|
+
],
|
48
|
+
"dependencies": {
|
49
|
+
"ansi-styles": "^4.0.0",
|
50
|
+
"string-width": "^4.1.0",
|
51
|
+
"strip-ansi": "^5.0.0"
|
52
|
+
},
|
53
|
+
"devDependencies": {
|
54
|
+
"ava": "^2.1.0",
|
55
|
+
"chalk": "^2.4.2",
|
56
|
+
"coveralls": "^3.0.3",
|
57
|
+
"has-ansi": "^3.0.0",
|
58
|
+
"nyc": "^14.1.1",
|
59
|
+
"xo": "^0.24.0"
|
60
|
+
}
|
62
61
|
}
|
package/readme.md
CHANGED
@@ -27,11 +27,11 @@ console.log(wrapAnsi(input, 20));
|
|
27
27
|
|
28
28
|
## API
|
29
29
|
|
30
|
-
### wrapAnsi(
|
30
|
+
### wrapAnsi(string, columns, options?)
|
31
31
|
|
32
32
|
Wrap words to the specified column width.
|
33
33
|
|
34
|
-
####
|
34
|
+
#### string
|
35
35
|
|
36
36
|
Type: `string`
|
37
37
|
|
@@ -45,7 +45,7 @@ Number of columns to wrap the text to.
|
|
45
45
|
|
46
46
|
#### options
|
47
47
|
|
48
|
-
Type: `
|
48
|
+
Type: `object`
|
49
49
|
|
50
50
|
##### hard
|
51
51
|
|
@@ -84,6 +84,14 @@ Whitespace on all lines is removed by default. Set this option to `false` if you
|
|
84
84
|
- [Benjamin Coe](https://github.com/bcoe)
|
85
85
|
|
86
86
|
|
87
|
-
|
87
|
+
---
|
88
88
|
|
89
|
-
|
89
|
+
<div align="center">
|
90
|
+
<b>
|
91
|
+
<a href="https://tidelift.com/subscription/pkg/npm-wrap_ansi?utm_source=npm-wrap-ansi&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
|
92
|
+
</b>
|
93
|
+
<br>
|
94
|
+
<sub>
|
95
|
+
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
|
96
|
+
</sub>
|
97
|
+
</div>
|