kodevu 0.1.17 → 0.1.19
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/package.json +1 -1
- package/src/progress-ui.js +90 -9
package/package.json
CHANGED
package/src/progress-ui.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import readline from "node:readline";
|
|
2
2
|
|
|
3
3
|
const SPINNER_FRAMES = ["|", "/", "-", "\\"];
|
|
4
|
+
const ELLIPSIS = "...";
|
|
5
|
+
const MIN_DYNAMIC_WIDTH = 60;
|
|
4
6
|
|
|
5
7
|
function clampProgress(value) {
|
|
6
8
|
if (!Number.isFinite(value)) {
|
|
@@ -10,12 +12,53 @@ function clampProgress(value) {
|
|
|
10
12
|
return Math.max(0, Math.min(1, value));
|
|
11
13
|
}
|
|
12
14
|
|
|
15
|
+
function getCharacterWidth(character) {
|
|
16
|
+
const codePoint = character.codePointAt(0);
|
|
17
|
+
|
|
18
|
+
if (!codePoint || codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) {
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (
|
|
23
|
+
codePoint >= 0x1100 &&
|
|
24
|
+
(
|
|
25
|
+
codePoint <= 0x115f ||
|
|
26
|
+
codePoint === 0x2329 ||
|
|
27
|
+
codePoint === 0x232a ||
|
|
28
|
+
(codePoint >= 0x2e80 && codePoint <= 0xa4cf && codePoint !== 0x303f) ||
|
|
29
|
+
(codePoint >= 0xac00 && codePoint <= 0xd7a3) ||
|
|
30
|
+
(codePoint >= 0xf900 && codePoint <= 0xfaff) ||
|
|
31
|
+
(codePoint >= 0xfe10 && codePoint <= 0xfe19) ||
|
|
32
|
+
(codePoint >= 0xfe30 && codePoint <= 0xfe6f) ||
|
|
33
|
+
(codePoint >= 0xff00 && codePoint <= 0xff60) ||
|
|
34
|
+
(codePoint >= 0xffe0 && codePoint <= 0xffe6) ||
|
|
35
|
+
(codePoint >= 0x1f300 && codePoint <= 0x1f64f) ||
|
|
36
|
+
(codePoint >= 0x1f900 && codePoint <= 0x1f9ff) ||
|
|
37
|
+
(codePoint >= 0x20000 && codePoint <= 0x3fffd)
|
|
38
|
+
)
|
|
39
|
+
) {
|
|
40
|
+
return 2;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return 1;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getDisplayWidth(text) {
|
|
47
|
+
let width = 0;
|
|
48
|
+
|
|
49
|
+
for (const character of text) {
|
|
50
|
+
width += getCharacterWidth(character);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return width;
|
|
54
|
+
}
|
|
55
|
+
|
|
13
56
|
function truncateLine(line, maxWidth) {
|
|
14
57
|
if (!Number.isFinite(maxWidth) || maxWidth <= 0) {
|
|
15
58
|
return "";
|
|
16
59
|
}
|
|
17
60
|
|
|
18
|
-
if (line
|
|
61
|
+
if (getDisplayWidth(line) <= maxWidth) {
|
|
19
62
|
return line;
|
|
20
63
|
}
|
|
21
64
|
|
|
@@ -23,7 +66,22 @@ function truncateLine(line, maxWidth) {
|
|
|
23
66
|
return ".".repeat(maxWidth);
|
|
24
67
|
}
|
|
25
68
|
|
|
26
|
-
|
|
69
|
+
const targetWidth = maxWidth - getDisplayWidth(ELLIPSIS);
|
|
70
|
+
let result = "";
|
|
71
|
+
let width = 0;
|
|
72
|
+
|
|
73
|
+
for (const character of line) {
|
|
74
|
+
const nextWidth = width + getCharacterWidth(character);
|
|
75
|
+
|
|
76
|
+
if (nextWidth > targetWidth) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
result += character;
|
|
81
|
+
width = nextWidth;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return `${result}${ELLIPSIS}`;
|
|
27
85
|
}
|
|
28
86
|
|
|
29
87
|
class ProgressItem {
|
|
@@ -40,7 +98,7 @@ class ProgressItem {
|
|
|
40
98
|
this.active = true;
|
|
41
99
|
this.stage = stage;
|
|
42
100
|
|
|
43
|
-
if (!this.display.
|
|
101
|
+
if (!this.display.canRenderDynamically()) {
|
|
44
102
|
this.writeFallback(`... ${this.label}: ${stage}`);
|
|
45
103
|
return;
|
|
46
104
|
}
|
|
@@ -56,11 +114,12 @@ class ProgressItem {
|
|
|
56
114
|
this.stage = stage;
|
|
57
115
|
}
|
|
58
116
|
|
|
59
|
-
if (!this.display.
|
|
117
|
+
if (!this.display.canRenderDynamically()) {
|
|
60
118
|
this.writeFallback(`... ${this.label}: ${this.stage}`);
|
|
61
119
|
return;
|
|
62
120
|
}
|
|
63
121
|
|
|
122
|
+
this.display.start();
|
|
64
123
|
this.display.activate(this);
|
|
65
124
|
}
|
|
66
125
|
|
|
@@ -117,6 +176,7 @@ export class ProgressDisplay {
|
|
|
117
176
|
this.items = [];
|
|
118
177
|
this.currentItem = null;
|
|
119
178
|
this.statusVisible = false;
|
|
179
|
+
this.lastStatusWidth = 0;
|
|
120
180
|
this.resizeAttached = false;
|
|
121
181
|
this.handleResize = this.handleResize.bind(this);
|
|
122
182
|
}
|
|
@@ -158,7 +218,7 @@ export class ProgressDisplay {
|
|
|
158
218
|
}
|
|
159
219
|
|
|
160
220
|
log(message) {
|
|
161
|
-
if (!this.
|
|
221
|
+
if (!this.canRenderDynamically()) {
|
|
162
222
|
this.stream.write(`${message}\n`);
|
|
163
223
|
return;
|
|
164
224
|
}
|
|
@@ -169,7 +229,7 @@ export class ProgressDisplay {
|
|
|
169
229
|
}
|
|
170
230
|
|
|
171
231
|
writeStaticLine(message) {
|
|
172
|
-
if (!this.
|
|
232
|
+
if (!this.canRenderDynamically()) {
|
|
173
233
|
this.stream.write(`${message}\n`);
|
|
174
234
|
return;
|
|
175
235
|
}
|
|
@@ -180,13 +240,16 @@ export class ProgressDisplay {
|
|
|
180
240
|
}
|
|
181
241
|
|
|
182
242
|
render() {
|
|
183
|
-
if (!this.
|
|
243
|
+
if (!this.canRenderDynamically() || !this.currentItem?.active) {
|
|
244
|
+
this.clearStatusLine();
|
|
184
245
|
return;
|
|
185
246
|
}
|
|
186
247
|
|
|
187
248
|
this.clearStatusLine();
|
|
188
|
-
this.
|
|
249
|
+
const line = this.currentItem.renderLine(this.frameIndex);
|
|
250
|
+
this.stream.write(line);
|
|
189
251
|
this.statusVisible = true;
|
|
252
|
+
this.lastStatusWidth = getDisplayWidth(line);
|
|
190
253
|
}
|
|
191
254
|
|
|
192
255
|
clearStatusLine() {
|
|
@@ -194,9 +257,23 @@ export class ProgressDisplay {
|
|
|
194
257
|
return;
|
|
195
258
|
}
|
|
196
259
|
|
|
197
|
-
|
|
260
|
+
const rows = Math.max(1, Math.ceil(this.lastStatusWidth / Math.max(this.stream.columns || 1, 1)));
|
|
261
|
+
|
|
262
|
+
readline.moveCursor(this.stream, 0, -Math.max(rows - 1, 0));
|
|
263
|
+
|
|
264
|
+
for (let index = 0; index < rows; index += 1) {
|
|
265
|
+
readline.clearLine(this.stream, 0);
|
|
266
|
+
readline.cursorTo(this.stream, 0);
|
|
267
|
+
|
|
268
|
+
if (index < rows - 1) {
|
|
269
|
+
readline.moveCursor(this.stream, 0, 1);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
readline.moveCursor(this.stream, 0, -Math.max(rows - 1, 0));
|
|
198
274
|
readline.cursorTo(this.stream, 0);
|
|
199
275
|
this.statusVisible = false;
|
|
276
|
+
this.lastStatusWidth = 0;
|
|
200
277
|
}
|
|
201
278
|
|
|
202
279
|
stopIfIdle() {
|
|
@@ -217,6 +294,10 @@ export class ProgressDisplay {
|
|
|
217
294
|
return Math.max(columns - 1, 1);
|
|
218
295
|
}
|
|
219
296
|
|
|
297
|
+
canRenderDynamically() {
|
|
298
|
+
return this.enabled && this.getAvailableWidth() >= MIN_DYNAMIC_WIDTH;
|
|
299
|
+
}
|
|
300
|
+
|
|
220
301
|
handleResize() {
|
|
221
302
|
if (!this.enabled) {
|
|
222
303
|
return;
|