cli-truncate 5.0.0 → 5.1.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.d.ts +3 -1
- package/index.js +76 -7
- package/package.json +1 -1
- package/readme.md +13 -9
package/index.d.ts
CHANGED
|
@@ -93,7 +93,9 @@ cliTruncate('unicorn', 4, {position: 'middle'});
|
|
|
93
93
|
//=> 'un…n'
|
|
94
94
|
|
|
95
95
|
cliTruncate('\u001B[31municorn\u001B[39m', 4);
|
|
96
|
-
//=> '\u001B[31muni
|
|
96
|
+
//=> '\u001B[31muni…\u001B[39m'
|
|
97
|
+
|
|
98
|
+
// Note: When truncating styled text (ANSI escapes), the truncation character inherits the style at the breaking point for `position: 'start'` and `position: 'end'`. This does not apply to `position: 'middle'`.
|
|
97
99
|
|
|
98
100
|
// Truncate Unicode surrogate pairs
|
|
99
101
|
cliTruncate('uni\uD83C\uDE00corn', 5);
|
package/index.js
CHANGED
|
@@ -49,21 +49,88 @@ export default function cliTruncate(text, columns, options = {}) {
|
|
|
49
49
|
return text;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
// ANSI escape sequence constants
|
|
53
|
+
const ANSI = {
|
|
54
|
+
ESC: 27,
|
|
55
|
+
LEFT_BRACKET: 91,
|
|
56
|
+
LETTER_M: 109,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const isSgrParameter = code => (code >= 48 && code <= 57) || code === 59; // 0-9 or ;
|
|
60
|
+
|
|
61
|
+
function leadingSgrSpanEndIndex(string) {
|
|
62
|
+
let index = 0;
|
|
63
|
+
while (index + 2 < string.length && string.codePointAt(index) === ANSI.ESC && string.codePointAt(index + 1) === ANSI.LEFT_BRACKET) {
|
|
64
|
+
let j = index + 2;
|
|
65
|
+
while (j < string.length && isSgrParameter(string.codePointAt(j))) {
|
|
66
|
+
j++;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (j < string.length && string.codePointAt(j) === ANSI.LETTER_M) {
|
|
70
|
+
index = j + 1;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return index;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function trailingSgrSpanStartIndex(string) {
|
|
81
|
+
let start = string.length;
|
|
82
|
+
while (start > 1 && string.codePointAt(start - 1) === ANSI.LETTER_M) {
|
|
83
|
+
let j = start - 2;
|
|
84
|
+
while (j >= 0 && isSgrParameter(string.codePointAt(j))) {
|
|
85
|
+
j--;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (j >= 1 && string.codePointAt(j - 1) === ANSI.ESC && string.codePointAt(j) === ANSI.LEFT_BRACKET) {
|
|
89
|
+
start = j - 1;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return start;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function appendWithInheritedStyleFromEnd(visible, suffix) {
|
|
100
|
+
const start = trailingSgrSpanStartIndex(visible);
|
|
101
|
+
if (start === visible.length) {
|
|
102
|
+
return visible + suffix;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return visible.slice(0, start) + suffix + visible.slice(start);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function prependWithInheritedStyleFromStart(prefix, visible) {
|
|
109
|
+
const end = leadingSgrSpanEndIndex(visible);
|
|
110
|
+
if (end === 0) {
|
|
111
|
+
return prefix + visible;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return visible.slice(0, end) + prefix + visible.slice(end);
|
|
115
|
+
}
|
|
116
|
+
|
|
52
117
|
if (position === 'start') {
|
|
53
118
|
if (preferTruncationOnSpace) {
|
|
54
119
|
const nearestSpace = getIndexOfNearestSpace(text, length - columns + 1, true);
|
|
55
|
-
|
|
120
|
+
const right = sliceAnsi(text, nearestSpace, length).trim();
|
|
121
|
+
return prependWithInheritedStyleFromStart(truncationCharacter, right);
|
|
56
122
|
}
|
|
57
123
|
|
|
58
|
-
if (space
|
|
124
|
+
if (space) {
|
|
59
125
|
truncationCharacter += ' ';
|
|
60
126
|
}
|
|
61
127
|
|
|
62
|
-
|
|
128
|
+
const right = sliceAnsi(text, length - columns + stringWidth(truncationCharacter), length);
|
|
129
|
+
return prependWithInheritedStyleFromStart(truncationCharacter, right);
|
|
63
130
|
}
|
|
64
131
|
|
|
65
132
|
if (position === 'middle') {
|
|
66
|
-
if (space
|
|
133
|
+
if (space) {
|
|
67
134
|
truncationCharacter = ` ${truncationCharacter} `;
|
|
68
135
|
}
|
|
69
136
|
|
|
@@ -85,14 +152,16 @@ export default function cliTruncate(text, columns, options = {}) {
|
|
|
85
152
|
if (position === 'end') {
|
|
86
153
|
if (preferTruncationOnSpace) {
|
|
87
154
|
const nearestSpace = getIndexOfNearestSpace(text, columns - 1);
|
|
88
|
-
|
|
155
|
+
const left = sliceAnsi(text, 0, nearestSpace);
|
|
156
|
+
return appendWithInheritedStyleFromEnd(left, truncationCharacter);
|
|
89
157
|
}
|
|
90
158
|
|
|
91
|
-
if (space
|
|
159
|
+
if (space) {
|
|
92
160
|
truncationCharacter = ` ${truncationCharacter}`;
|
|
93
161
|
}
|
|
94
162
|
|
|
95
|
-
|
|
163
|
+
const left = sliceAnsi(text, 0, columns - stringWidth(truncationCharacter));
|
|
164
|
+
return appendWithInheritedStyleFromEnd(left, truncationCharacter);
|
|
96
165
|
}
|
|
97
166
|
|
|
98
167
|
throw new Error(`Expected \`options.position\` to be either \`start\`, \`middle\` or \`end\`, got ${position}`);
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -25,11 +25,14 @@ cliTruncate('unicorn', 4, {position: 'start'});
|
|
|
25
25
|
cliTruncate('unicorn', 4, {position: 'middle'});
|
|
26
26
|
//=> 'un…n'
|
|
27
27
|
|
|
28
|
-
cliTruncate('unicorns rainbow dragons', 6, {position: 'end'})
|
|
28
|
+
cliTruncate('unicorns rainbow dragons', 6, {position: 'end'});
|
|
29
29
|
//=> 'unico…'
|
|
30
30
|
|
|
31
31
|
cliTruncate('\u001B[31municorn\u001B[39m', 4);
|
|
32
|
-
//=> '\u001B[31muni
|
|
32
|
+
//=> '\u001B[31muni…\u001B[39m'
|
|
33
|
+
|
|
34
|
+
> [!NOTE]
|
|
35
|
+
> When truncating styled text (ANSI escapes), the truncation character inherits the style at the breaking point for `position: 'start'` and `position: 'end'`. This does not apply to `position: 'middle'`.
|
|
33
36
|
|
|
34
37
|
// Truncate Unicode surrogate pairs
|
|
35
38
|
cliTruncate('uni\uD83C\uDE00corn', 5);
|
|
@@ -106,21 +109,21 @@ Truncate the string from a whitespace if it is within 3 characters from the actu
|
|
|
106
109
|
```js
|
|
107
110
|
import cliTruncate from 'cli-truncate';
|
|
108
111
|
|
|
109
|
-
cliTruncate('unicorns rainbow dragons', 20, {position: 'start', preferTruncationOnSpace: true})
|
|
112
|
+
cliTruncate('unicorns rainbow dragons', 20, {position: 'start', preferTruncationOnSpace: true});
|
|
110
113
|
//=> '…rainbow dragons'
|
|
111
114
|
|
|
112
|
-
//
|
|
113
|
-
cliTruncate('unicorns rainbow dragons', 20, {position: 'start'})
|
|
115
|
+
// Without preferTruncationOnSpace
|
|
116
|
+
cliTruncate('unicorns rainbow dragons', 20, {position: 'start'});
|
|
114
117
|
//=> '…rns rainbow dragons'
|
|
115
118
|
|
|
116
|
-
cliTruncate('unicorns rainbow dragons', 20, {position: 'middle', preferTruncationOnSpace: true})
|
|
119
|
+
cliTruncate('unicorns rainbow dragons', 20, {position: 'middle', preferTruncationOnSpace: true});
|
|
117
120
|
//=> 'unicorns…dragons'
|
|
118
121
|
|
|
119
|
-
cliTruncate('unicorns rainbow dragons', 6, {position: 'end', preferTruncationOnSpace: true})
|
|
122
|
+
cliTruncate('unicorns rainbow dragons', 6, {position: 'end', preferTruncationOnSpace: true});
|
|
120
123
|
//=> 'unico…'
|
|
121
124
|
|
|
122
|
-
// preferTruncationOnSpace
|
|
123
|
-
cliTruncate('unicorns rainbow dragons', 6, {position: 'middle', preferTruncationOnSpace: true})
|
|
125
|
+
// preferTruncationOnSpace has no effect if space isn't found within 3 characters
|
|
126
|
+
cliTruncate('unicorns rainbow dragons', 6, {position: 'middle', preferTruncationOnSpace: true});
|
|
124
127
|
//=> 'uni…ns'
|
|
125
128
|
```
|
|
126
129
|
|
|
@@ -142,6 +145,7 @@ cliTruncate('unicorns', 5, {position: 'end', truncationCharacter: '.'});
|
|
|
142
145
|
|
|
143
146
|
cliTruncate('unicorns', 5, {position: 'end', truncationCharacter: ''});
|
|
144
147
|
//=> 'unico'
|
|
148
|
+
|
|
145
149
|
```
|
|
146
150
|
|
|
147
151
|
## Related
|