console-toolkit 1.2.14 → 1.3.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/LICENSE +1 -1
- package/README.md +4 -0
- package/llms-full.txt +64 -4
- package/package.json +6 -6
- package/src/alphanumeric/arrows.js +0 -23
- package/src/alphanumeric/fractions.js +0 -49
- package/src/alphanumeric/number-formatters.js +0 -44
- package/src/alphanumeric/roman.js +0 -12
- package/src/alphanumeric/unicode-cultural-numbers.js +0 -1
- package/src/alphanumeric/unicode-letters.js +0 -8
- package/src/alphanumeric/unicode-numbers.js +0 -21
- package/src/alphanumeric/utils.js +0 -26
- package/src/ansi/csi.js +0 -49
- package/src/ansi/sgr-state.js +7 -50
- package/src/ansi/sgr.js +0 -420
- package/src/box.d.ts +4 -1
- package/src/box.js +15 -115
- package/src/charts/bars/block-frac-grouped.js +0 -6
- package/src/charts/bars/block-frac.js +1 -14
- package/src/charts/bars/block-grouped.js +0 -6
- package/src/charts/bars/block.js +1 -14
- package/src/charts/bars/draw-grouped.js +0 -4
- package/src/charts/bars/draw-stacked.js +0 -4
- package/src/charts/bars/frac-grouped.js +2 -14
- package/src/charts/bars/plain-grouped.js +0 -6
- package/src/charts/bars/plain.js +1 -28
- package/src/charts/columns/block-frac-grouped.js +0 -6
- package/src/charts/columns/block-frac.js +0 -13
- package/src/charts/columns/block-grouped.js +0 -6
- package/src/charts/columns/block.js +0 -13
- package/src/charts/columns/draw-grouped.js +1 -5
- package/src/charts/columns/draw-stacked.js +0 -4
- package/src/charts/columns/frac-grouped.js +1 -13
- package/src/charts/columns/plain-grouped.js +0 -6
- package/src/charts/columns/plain.js +0 -13
- package/src/charts/themes/default.js +0 -1
- package/src/charts/themes/rainbow-reversed.js +0 -1
- package/src/charts/themes/rainbow.js +0 -1
- package/src/charts/utils.js +2 -28
- package/src/draw-block-frac.js +0 -14
- package/src/draw-block.js +0 -24
- package/src/meta.js +0 -64
- package/src/output/show.d.ts +8 -3
- package/src/output/show.js +7 -38
- package/src/output/updater.d.ts +8 -3
- package/src/output/updater.js +4 -51
- package/src/output/writer.js +1 -53
- package/src/panel.d.ts +16 -10
- package/src/panel.js +21 -276
- package/src/plot/bitmap.js +5 -33
- package/src/plot/draw-line.js +0 -8
- package/src/plot/draw-rect.js +25 -103
- package/src/plot/index.js +0 -22
- package/src/plot/to-quads.js +3 -6
- package/src/spinner/spin.js +23 -20
- package/src/spinner/spinner.d.ts +16 -2
- package/src/spinner/spinner.js +22 -34
- package/src/spinner/spinners.js +0 -16
- package/src/strings/clip.js +0 -10
- package/src/strings/parse.js +0 -7
- package/src/strings/split.js +0 -15
- package/src/strings.d.ts +2 -0
- package/src/strings.js +2 -32
- package/src/style.js +2 -58
- package/src/symbols.js +0 -84
- package/src/table/draw-borders.js +0 -9
- package/src/table/index.d.ts +1 -1
- package/src/table/index.js +0 -1
- package/src/table/table.js +3 -58
- package/src/themes/blocks/unicode-half.js +0 -1
- package/src/themes/blocks/unicode-thin.js +0 -1
- package/src/themes/lines/ascii-compact.js +5 -9
- package/src/themes/lines/ascii-dots.js +2 -7
- package/src/themes/lines/ascii-girder.js +4 -7
- package/src/themes/lines/ascii-github.js +5 -9
- package/src/themes/lines/ascii-reddit.js +5 -9
- package/src/themes/lines/ascii-rounded.js +5 -9
- package/src/themes/lines/ascii.js +5 -9
- package/src/themes/lines/unicode-bold.js +8 -14
- package/src/themes/lines/unicode-rounded.js +8 -14
- package/src/themes/lines/unicode.js +8 -14
- package/src/themes/utils.d.ts +6 -0
- package/src/themes/utils.js +6 -7
- package/src/turtle/draw-line-art.js +26 -18
- package/src/turtle/draw-unicode.js +0 -8
- package/src/turtle/index.d.ts +1 -1
- package/src/turtle/index.js +0 -8
- package/src/turtle/turtle.js +0 -120
package/src/plot/bitmap.js
CHANGED
|
@@ -2,16 +2,7 @@ import Box from '../box.js';
|
|
|
2
2
|
import {addAlias} from '../meta.js';
|
|
3
3
|
import {fullBlock} from '../symbols.js';
|
|
4
4
|
|
|
5
|
-
/** A bitmap image using a compact bit-packed representation.
|
|
6
|
-
* Supports setting/getting individual bits and converting to a Box for console display.
|
|
7
|
-
*/
|
|
8
5
|
export class Bitmap {
|
|
9
|
-
/** Creates a new Bitmap.
|
|
10
|
-
* @param {number} width - The width in pixels.
|
|
11
|
-
* @param {number} height - The height in pixels.
|
|
12
|
-
* @param {number} [blockWidth=5] - The width of each internal block (blockWidth * blockHeight <= 32).
|
|
13
|
-
* @param {number} [blockHeight=5] - The height of each internal block.
|
|
14
|
-
*/
|
|
15
6
|
constructor(width, height, blockWidth = 5, blockHeight = 5) {
|
|
16
7
|
// parameters check
|
|
17
8
|
width = Math.round(width);
|
|
@@ -58,11 +49,6 @@ export class Bitmap {
|
|
|
58
49
|
return 1 << (shiftX + this.blockWidth * shiftY);
|
|
59
50
|
}
|
|
60
51
|
|
|
61
|
-
/** Gets the value of a bit at the given position.
|
|
62
|
-
* @param {number} x - The x coordinate.
|
|
63
|
-
* @param {number} y - The y coordinate.
|
|
64
|
-
* @returns {number} Non-zero if the bit is set, 0 otherwise.
|
|
65
|
-
*/
|
|
66
52
|
getBit(x, y) {
|
|
67
53
|
if (x < 0 || x >= this.width || y < 0 || y >= this.height) return 0;
|
|
68
54
|
const index = this.getWordIndex(x, y),
|
|
@@ -70,12 +56,6 @@ export class Bitmap {
|
|
|
70
56
|
return this.bitmap[index] & mask;
|
|
71
57
|
}
|
|
72
58
|
|
|
73
|
-
/** Sets or clears a bit at the given position.
|
|
74
|
-
* @param {number} x - The x coordinate.
|
|
75
|
-
* @param {number} y - The y coordinate.
|
|
76
|
-
* @param {number} [value=1] - Positive to set, 0 to clear, negative to toggle.
|
|
77
|
-
* @returns {this}
|
|
78
|
-
*/
|
|
79
59
|
setBit(x, y, value = 1) {
|
|
80
60
|
if (x < 0 || x >= this.width || y < 0 || y >= this.height) return this;
|
|
81
61
|
const index = this.getWordIndex(x, y),
|
|
@@ -85,10 +65,6 @@ export class Bitmap {
|
|
|
85
65
|
return this;
|
|
86
66
|
}
|
|
87
67
|
|
|
88
|
-
/** Clears the entire bitmap.
|
|
89
|
-
* @param {boolean} [value=false] - If true, sets all bits; if false, clears all bits.
|
|
90
|
-
* @returns {this}
|
|
91
|
-
*/
|
|
92
68
|
clear(value) {
|
|
93
69
|
this.bitmap.fill(value ? ~0 : 0);
|
|
94
70
|
return this;
|
|
@@ -105,27 +81,23 @@ export class Bitmap {
|
|
|
105
81
|
// return result;
|
|
106
82
|
// }
|
|
107
83
|
|
|
108
|
-
/** Converts the bitmap to a Box for console display.
|
|
109
|
-
* @param {string} [one=fullBlock] - Character for set bits.
|
|
110
|
-
* @param {string} [zero=' '] - Character for unset bits.
|
|
111
|
-
* @returns {import('../box.js').Box} A Box representation of the bitmap.
|
|
112
|
-
*/
|
|
113
84
|
toBox(one = fullBlock, zero = ' ') {
|
|
114
|
-
const result = []
|
|
85
|
+
const result = [],
|
|
86
|
+
chars = new Array(this.width);
|
|
115
87
|
for (let k = 0, kBase = 0; k < this.lineCount; ++k, kBase += this.blockHeight) {
|
|
116
88
|
const iLimit = Math.min(this.blockHeight, this.height - kBase);
|
|
117
89
|
for (let i = 0; i < iLimit; ++i) {
|
|
118
|
-
let
|
|
90
|
+
let pos = 0;
|
|
119
91
|
for (let j = 0, jBase = 0; j < this.lineSize; ++j, jBase += this.blockWidth) {
|
|
120
92
|
const index = k * this.lineSize + j,
|
|
121
93
|
word = this.bitmap[index],
|
|
122
94
|
mLimit = Math.min(this.blockWidth, this.width - jBase);
|
|
123
95
|
let mask = 1 << (this.blockWidth * i);
|
|
124
96
|
for (let m = 0; m < mLimit; ++m, mask <<= 1) {
|
|
125
|
-
|
|
97
|
+
chars[pos++] = word & mask ? one : zero;
|
|
126
98
|
}
|
|
127
99
|
}
|
|
128
|
-
result.push(
|
|
100
|
+
result.push(chars.join(''));
|
|
129
101
|
}
|
|
130
102
|
}
|
|
131
103
|
return new Box(result, true);
|
package/src/plot/draw-line.js
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
// Drawing lines using Bresenham's line algorithm
|
|
2
2
|
// The canonic version from https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
|
|
3
3
|
|
|
4
|
-
/** Draws a line on a Bitmap using Bresenham's line algorithm.
|
|
5
|
-
* @param {import('./bitmap.js').Bitmap} bmp - The bitmap to draw on.
|
|
6
|
-
* @param {number} x0 - Start x coordinate.
|
|
7
|
-
* @param {number} y0 - Start y coordinate.
|
|
8
|
-
* @param {number} x1 - End x coordinate.
|
|
9
|
-
* @param {number} y1 - End y coordinate.
|
|
10
|
-
* @param {number} [value=1] - Bit value: positive to set, 0 to clear, negative to toggle.
|
|
11
|
-
*/
|
|
12
4
|
export const drawLine = (bmp, x0, y0, x1, y1, value = 1) => {
|
|
13
5
|
const dx = Math.abs(x1 - x0),
|
|
14
6
|
sx = x0 < x1 ? 1 : -1,
|
package/src/plot/draw-rect.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
/** Draws a filled rectangle on a Bitmap by efficiently manipulating the underlying bit array.
|
|
2
|
-
* @param {import('./bitmap.js').Bitmap} bmp - The bitmap to draw on.
|
|
3
|
-
* @param {number} x0 - First corner x coordinate.
|
|
4
|
-
* @param {number} y0 - First corner y coordinate.
|
|
5
|
-
* @param {number} x1 - Opposite corner x coordinate.
|
|
6
|
-
* @param {number} y1 - Opposite corner y coordinate.
|
|
7
|
-
* @param {number} [value=1] - Bit value: positive to set, 0 to clear, negative to toggle.
|
|
8
|
-
*/
|
|
9
1
|
export const drawRect = (bmp, x0, y0, x1, y1, value = 1) => {
|
|
10
2
|
if (x1 < x0) [x0, x1] = [x1, x0];
|
|
11
3
|
if (y1 < y0) [y0, y1] = [y1, y0];
|
|
12
4
|
|
|
5
|
+
// hoist op-mode once: + = set (OR), - = toggle (XOR), 0 = clear (AND~)
|
|
6
|
+
const apply =
|
|
7
|
+
value > 0
|
|
8
|
+
? (current, mask) => current | mask
|
|
9
|
+
: value < 0
|
|
10
|
+
? (current, mask) => current ^ mask
|
|
11
|
+
: (current, mask) => current & ~mask;
|
|
12
|
+
const applyFull = value > 0 ? () => ~0 : value < 0 ? current => ~current : () => 0;
|
|
13
|
+
|
|
13
14
|
let indexL = bmp.getWordIndex(x0, y0),
|
|
14
15
|
indexR = bmp.getWordIndex(x1, y0);
|
|
15
16
|
|
|
@@ -30,12 +31,7 @@ export const drawRect = (bmp, x0, y0, x1, y1, value = 1) => {
|
|
|
30
31
|
for (let i = 1; i < height; ++i) fullMask = (fullMask << bmp.blockWidth) | mask;
|
|
31
32
|
fullMask <<= firstRowShift;
|
|
32
33
|
|
|
33
|
-
bmp.bitmap[indexL] =
|
|
34
|
-
value > 0
|
|
35
|
-
? bmp.bitmap[indexL] | fullMask
|
|
36
|
-
: value < 0
|
|
37
|
-
? bmp.bitmap[indexL] ^ fullMask
|
|
38
|
-
: bmp.bitmap[indexL] & ~fullMask;
|
|
34
|
+
bmp.bitmap[indexL] = apply(bmp.bitmap[indexL], fullMask);
|
|
39
35
|
return;
|
|
40
36
|
}
|
|
41
37
|
|
|
@@ -56,25 +52,9 @@ export const drawRect = (bmp, x0, y0, x1, y1, value = 1) => {
|
|
|
56
52
|
fullMaskR <<= firstRowShift;
|
|
57
53
|
|
|
58
54
|
// apply masks
|
|
59
|
-
bmp.bitmap[indexL] =
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
: value < 0
|
|
63
|
-
? bmp.bitmap[indexL] ^ fullMaskL
|
|
64
|
-
: bmp.bitmap[indexL] & ~fullMaskL;
|
|
65
|
-
for (let index = indexL + 1; index < indexR; ++index)
|
|
66
|
-
bmp.bitmap[index] =
|
|
67
|
-
value > 0
|
|
68
|
-
? bmp.bitmap[index] | fullMaskM
|
|
69
|
-
: value < 0
|
|
70
|
-
? bmp.bitmap[index] ^ fullMaskM
|
|
71
|
-
: bmp.bitmap[index] & ~fullMaskM;
|
|
72
|
-
bmp.bitmap[indexR] =
|
|
73
|
-
value > 0
|
|
74
|
-
? bmp.bitmap[indexR] | fullMaskR
|
|
75
|
-
: value < 0
|
|
76
|
-
? bmp.bitmap[indexR] ^ fullMaskR
|
|
77
|
-
: bmp.bitmap[indexR] & ~fullMaskR;
|
|
55
|
+
bmp.bitmap[indexL] = apply(bmp.bitmap[indexL], fullMaskL);
|
|
56
|
+
for (let index = indexL + 1; index < indexR; ++index) bmp.bitmap[index] = apply(bmp.bitmap[index], fullMaskM);
|
|
57
|
+
bmp.bitmap[indexR] = apply(bmp.bitmap[indexR], fullMaskR);
|
|
78
58
|
return;
|
|
79
59
|
}
|
|
80
60
|
|
|
@@ -90,12 +70,7 @@ export const drawRect = (bmp, x0, y0, x1, y1, value = 1) => {
|
|
|
90
70
|
let fullMask = mask;
|
|
91
71
|
for (let i = 1, n = bmp.blockHeight - firstRows; i < n; ++i) fullMask = (fullMask << bmp.blockWidth) | mask;
|
|
92
72
|
fullMask <<= firstRowShift;
|
|
93
|
-
bmp.bitmap[indexL] =
|
|
94
|
-
value > 0
|
|
95
|
-
? bmp.bitmap[indexL] | fullMask
|
|
96
|
-
: value < 0
|
|
97
|
-
? bmp.bitmap[indexL] ^ fullMask
|
|
98
|
-
: bmp.bitmap[indexL] & ~fullMask;
|
|
73
|
+
bmp.bitmap[indexL] = apply(bmp.bitmap[indexL], fullMask);
|
|
99
74
|
indexL += bmp.lineSize;
|
|
100
75
|
}
|
|
101
76
|
if (fullLines) {
|
|
@@ -104,23 +79,13 @@ export const drawRect = (bmp, x0, y0, x1, y1, value = 1) => {
|
|
|
104
79
|
for (let i = 1; i < bmp.blockHeight; ++i) fullMask = (fullMask << bmp.blockWidth) | mask;
|
|
105
80
|
// apply the mask to full blocks
|
|
106
81
|
for (let i = 0; i < fullLines; ++i, indexL += bmp.lineSize)
|
|
107
|
-
bmp.bitmap[indexL] =
|
|
108
|
-
value > 0
|
|
109
|
-
? bmp.bitmap[indexL] | fullMask
|
|
110
|
-
: value < 0
|
|
111
|
-
? bmp.bitmap[indexL] ^ fullMask
|
|
112
|
-
: bmp.bitmap[indexL] & ~fullMask;
|
|
82
|
+
bmp.bitmap[indexL] = apply(bmp.bitmap[indexL], fullMask);
|
|
113
83
|
}
|
|
114
84
|
if (lastRows) {
|
|
115
85
|
// apply the mask to the last incomplete block
|
|
116
86
|
let fullMask = mask;
|
|
117
87
|
for (let i = 1; i < lastRows; ++i) fullMask = (fullMask << bmp.blockWidth) | mask;
|
|
118
|
-
bmp.bitmap[indexL] =
|
|
119
|
-
value > 0
|
|
120
|
-
? bmp.bitmap[indexL] | fullMask
|
|
121
|
-
: value < 0
|
|
122
|
-
? bmp.bitmap[indexL] ^ fullMask
|
|
123
|
-
: bmp.bitmap[indexL] & ~fullMask;
|
|
88
|
+
bmp.bitmap[indexL] = apply(bmp.bitmap[indexL], fullMask);
|
|
124
89
|
}
|
|
125
90
|
return;
|
|
126
91
|
}
|
|
@@ -140,25 +105,9 @@ export const drawRect = (bmp, x0, y0, x1, y1, value = 1) => {
|
|
|
140
105
|
}
|
|
141
106
|
fullMaskL <<= firstRowShift;
|
|
142
107
|
fullMaskR <<= firstRowShift;
|
|
143
|
-
bmp.bitmap[indexL] =
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
: value < 0
|
|
147
|
-
? bmp.bitmap[indexL] ^ fullMaskL
|
|
148
|
-
: bmp.bitmap[indexL] & ~fullMaskL;
|
|
149
|
-
for (let index = indexL + 1; index < indexR; ++index)
|
|
150
|
-
bmp.bitmap[index] =
|
|
151
|
-
value > 0
|
|
152
|
-
? bmp.bitmap[index] | fullMaskM
|
|
153
|
-
: value < 0
|
|
154
|
-
? bmp.bitmap[index] ^ fullMaskM
|
|
155
|
-
: bmp.bitmap[index] & ~fullMaskM;
|
|
156
|
-
bmp.bitmap[indexR] =
|
|
157
|
-
value > 0
|
|
158
|
-
? bmp.bitmap[indexR] | fullMaskR
|
|
159
|
-
: value < 0
|
|
160
|
-
? bmp.bitmap[indexR] ^ fullMaskR
|
|
161
|
-
: bmp.bitmap[indexR] & ~fullMaskR;
|
|
108
|
+
bmp.bitmap[indexL] = apply(bmp.bitmap[indexL], fullMaskL);
|
|
109
|
+
for (let index = indexL + 1; index < indexR; ++index) bmp.bitmap[index] = apply(bmp.bitmap[index], fullMaskM);
|
|
110
|
+
bmp.bitmap[indexR] = apply(bmp.bitmap[indexR], fullMaskR);
|
|
162
111
|
indexL += bmp.lineSize;
|
|
163
112
|
indexR += bmp.lineSize;
|
|
164
113
|
}
|
|
@@ -173,20 +122,9 @@ export const drawRect = (bmp, x0, y0, x1, y1, value = 1) => {
|
|
|
173
122
|
}
|
|
174
123
|
// apply masks
|
|
175
124
|
for (let i = 0; i < fullLines; ++i, indexL += bmp.lineSize, indexR += bmp.lineSize) {
|
|
176
|
-
bmp.bitmap[indexL] =
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
: value < 0
|
|
180
|
-
? bmp.bitmap[indexL] ^ fullMaskL
|
|
181
|
-
: bmp.bitmap[indexL] & ~fullMaskL;
|
|
182
|
-
for (let index = indexL + 1; index < indexR; ++index)
|
|
183
|
-
bmp.bitmap[index] = value > 0 ? ~0 : value < 0 ? ~bmp.bitmap[index] : 0;
|
|
184
|
-
bmp.bitmap[indexR] =
|
|
185
|
-
value > 0
|
|
186
|
-
? bmp.bitmap[indexR] | fullMaskR
|
|
187
|
-
: value < 0
|
|
188
|
-
? bmp.bitmap[indexR] ^ fullMaskR
|
|
189
|
-
: bmp.bitmap[indexR] & ~fullMaskR;
|
|
125
|
+
bmp.bitmap[indexL] = apply(bmp.bitmap[indexL], fullMaskL);
|
|
126
|
+
for (let index = indexL + 1; index < indexR; ++index) bmp.bitmap[index] = applyFull(bmp.bitmap[index]);
|
|
127
|
+
bmp.bitmap[indexR] = apply(bmp.bitmap[indexR], fullMaskR);
|
|
190
128
|
}
|
|
191
129
|
}
|
|
192
130
|
|
|
@@ -199,25 +137,9 @@ export const drawRect = (bmp, x0, y0, x1, y1, value = 1) => {
|
|
|
199
137
|
fullMaskL = (fullMaskL << bmp.blockWidth) | maskL;
|
|
200
138
|
fullMaskR = (fullMaskR << bmp.blockWidth) | maskR;
|
|
201
139
|
}
|
|
202
|
-
bmp.bitmap[indexL] =
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
: value < 0
|
|
206
|
-
? bmp.bitmap[indexL] ^ fullMaskL
|
|
207
|
-
: bmp.bitmap[indexL] & ~fullMaskL;
|
|
208
|
-
for (let index = indexL + 1; index < indexR; ++index)
|
|
209
|
-
bmp.bitmap[index] =
|
|
210
|
-
value > 0
|
|
211
|
-
? bmp.bitmap[index] | fullMaskM
|
|
212
|
-
: value < 0
|
|
213
|
-
? bmp.bitmap[index] ^ fullMaskM
|
|
214
|
-
: bmp.bitmap[index] & ~fullMaskM;
|
|
215
|
-
bmp.bitmap[indexR] =
|
|
216
|
-
value > 0
|
|
217
|
-
? bmp.bitmap[indexR] | fullMaskR
|
|
218
|
-
: value < 0
|
|
219
|
-
? bmp.bitmap[indexR] ^ fullMaskR
|
|
220
|
-
: bmp.bitmap[indexR] & ~fullMaskR;
|
|
140
|
+
bmp.bitmap[indexL] = apply(bmp.bitmap[indexL], fullMaskL);
|
|
141
|
+
for (let index = indexL + 1; index < indexR; ++index) bmp.bitmap[index] = apply(bmp.bitmap[index], fullMaskM);
|
|
142
|
+
bmp.bitmap[indexR] = apply(bmp.bitmap[indexR], fullMaskR);
|
|
221
143
|
}
|
|
222
144
|
};
|
|
223
145
|
|
package/src/plot/index.js
CHANGED
|
@@ -5,39 +5,17 @@ import toQuads from './to-quads.js';
|
|
|
5
5
|
|
|
6
6
|
// patch Bitmap
|
|
7
7
|
|
|
8
|
-
/** Draws a line on this bitmap.
|
|
9
|
-
* @param {number} x0 - Start X.
|
|
10
|
-
* @param {number} y0 - Start Y.
|
|
11
|
-
* @param {number} x1 - End X.
|
|
12
|
-
* @param {number} y1 - End Y.
|
|
13
|
-
* @param {number} [value=1] - Bit value.
|
|
14
|
-
* @returns {this}
|
|
15
|
-
*/
|
|
16
8
|
Bitmap.prototype.line = function (...args) {
|
|
17
9
|
drawLine(this, ...args);
|
|
18
10
|
return this;
|
|
19
11
|
};
|
|
20
|
-
/** Draws a filled rectangle on this bitmap.
|
|
21
|
-
* @param {number} x0 - First corner x coordinate.
|
|
22
|
-
* @param {number} y0 - First corner y coordinate.
|
|
23
|
-
* @param {number} x1 - Opposite corner x coordinate.
|
|
24
|
-
* @param {number} y1 - Opposite corner y coordinate.
|
|
25
|
-
* @param {number} [value=1] - Bit value.
|
|
26
|
-
* @returns {this}
|
|
27
|
-
*/
|
|
28
12
|
Bitmap.prototype.rect = function (...args) {
|
|
29
13
|
drawRect(this, ...args);
|
|
30
14
|
return this;
|
|
31
15
|
};
|
|
32
|
-
/** Converts this bitmap to a Box using quadrant characters.
|
|
33
|
-
* @returns {import('../box.js').default}
|
|
34
|
-
*/
|
|
35
16
|
Bitmap.prototype.toQuads = function () {
|
|
36
17
|
return toQuads(this);
|
|
37
18
|
};
|
|
38
|
-
/** Converts this bitmap to a string array via `toBox()`.
|
|
39
|
-
* @returns {string[]}
|
|
40
|
-
*/
|
|
41
19
|
Bitmap.prototype.toStrings = function () {
|
|
42
20
|
return this.toBox().toStrings();
|
|
43
21
|
};
|
package/src/plot/to-quads.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import Box from '../box.js';
|
|
2
2
|
import {quadrants} from '../symbols.js';
|
|
3
3
|
|
|
4
|
-
/** Converts a Bitmap to a Box using Unicode quadrant characters (2x2 pixels per character).
|
|
5
|
-
* Provides higher resolution representation than `toBox()`.
|
|
6
|
-
* @param {import('./bitmap.js').Bitmap} bmp - The bitmap to convert.
|
|
7
|
-
* @returns {import('../box.js').Box} A Box with quadrant characters.
|
|
8
|
-
*/
|
|
9
4
|
export const toQuads = bmp => {
|
|
10
5
|
const result = [],
|
|
11
6
|
rowSize = Math.floor((bmp.width + 1) / 2),
|
|
@@ -23,7 +18,9 @@ export const toQuads = bmp => {
|
|
|
23
18
|
}
|
|
24
19
|
}
|
|
25
20
|
if ((kBase + i) & 1) {
|
|
26
|
-
|
|
21
|
+
let row = '';
|
|
22
|
+
for (const k of accumulator) row += quadrants[k];
|
|
23
|
+
result.push(row);
|
|
27
24
|
if (kBase + i + 1 < bmp.height) accumulator.fill(0);
|
|
28
25
|
}
|
|
29
26
|
}
|
package/src/spinner/spin.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import {SpinnerBase} from './spinner.js';
|
|
2
2
|
|
|
3
|
-
/** Internal composite spinner that handles multiple spinner parts and functions via tagged template literals. */
|
|
4
3
|
class Spinner extends SpinnerBase {
|
|
5
|
-
/** @param {TemplateStringsArray} strings - Template literal strings.
|
|
6
|
-
* @param {any[]} args - Interpolated values.
|
|
7
|
-
*/
|
|
8
4
|
constructor(strings, args) {
|
|
9
5
|
super(false);
|
|
10
6
|
this.strings = strings;
|
|
@@ -12,9 +8,28 @@ class Spinner extends SpinnerBase {
|
|
|
12
8
|
this.indices = new WeakMap();
|
|
13
9
|
}
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
tick() {
|
|
12
|
+
for (const arg of this.args) {
|
|
13
|
+
if (arg instanceof SpinnerBase) {
|
|
14
|
+
arg.active = this.active;
|
|
15
|
+
arg.paused = this.paused;
|
|
16
|
+
arg.finished = this.finished;
|
|
17
|
+
arg.tick();
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(arg)) {
|
|
21
|
+
if (!this.indices.has(arg)) {
|
|
22
|
+
this.indices.set(arg, 0);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (!this.finished && !this.paused && this.active) {
|
|
26
|
+
this.indices.set(arg, (this.indices.get(arg) + 1) % arg.length);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
|
|
18
33
|
getFrame() {
|
|
19
34
|
let result = '';
|
|
20
35
|
for (let i = 0; i < this.args.length; ++i) {
|
|
@@ -28,18 +43,12 @@ class Spinner extends SpinnerBase {
|
|
|
28
43
|
}
|
|
29
44
|
|
|
30
45
|
if (arg instanceof SpinnerBase) {
|
|
31
|
-
arg.active = this.active;
|
|
32
|
-
arg.paused = this.paused;
|
|
33
|
-
arg.finished = this.finished;
|
|
34
46
|
result += arg.getFrame();
|
|
35
47
|
continue;
|
|
36
48
|
}
|
|
37
49
|
|
|
38
50
|
if (Array.isArray(arg)) {
|
|
39
|
-
|
|
40
|
-
const index = this.indices.get(arg);
|
|
41
|
-
if (!this.finished && !this.paused && this.active) this.indices.set(arg, (index + 1) % arg.length);
|
|
42
|
-
result += String(arg[index]);
|
|
51
|
+
result += String(arg[this.indices.get(arg) ?? 0]);
|
|
43
52
|
continue;
|
|
44
53
|
}
|
|
45
54
|
|
|
@@ -51,12 +60,6 @@ class Spinner extends SpinnerBase {
|
|
|
51
60
|
}
|
|
52
61
|
}
|
|
53
62
|
|
|
54
|
-
/** Tagged template literal function that creates a composite spinner.
|
|
55
|
-
* Arguments can be string arrays (cycled through), functions `(state) => string`, or SpinnerBase instances.
|
|
56
|
-
* @param {TemplateStringsArray} strings - Template literal strings.
|
|
57
|
-
* @param {...(string[]|Function|import('./spinner.js').SpinnerBase|*)} args - Interpolated values.
|
|
58
|
-
* @returns {import('./spinner.js').SpinnerBase} A composite spinner.
|
|
59
|
-
*/
|
|
60
63
|
const spin = (strings, ...args) => new Spinner(strings, args);
|
|
61
64
|
|
|
62
65
|
export default spin;
|
package/src/spinner/spinner.d.ts
CHANGED
|
@@ -31,10 +31,19 @@ export class SpinnerBase {
|
|
|
31
31
|
* @returns The next frame index.
|
|
32
32
|
*/
|
|
33
33
|
nextFrameIndex(length: number): number;
|
|
34
|
-
/**
|
|
34
|
+
/** Advances internal state by one step (state-aware: only advances when active+!paused or in finished/notStarted modes).
|
|
35
|
+
* Pure mutation — call `getFrame()` after to read the new frame.
|
|
36
|
+
* @returns This instance.
|
|
37
|
+
*/
|
|
38
|
+
tick(): this;
|
|
39
|
+
/** Returns the frame string at the current index. Read-only — does not mutate.
|
|
35
40
|
* @returns The frame string.
|
|
36
41
|
*/
|
|
37
42
|
getFrame(): string;
|
|
43
|
+
/** Convenience: calls `tick()` then `getFrame()`. Equivalent to the pre-1.3 `getFrame()` advance-and-return.
|
|
44
|
+
* @returns The frame string at the new index.
|
|
45
|
+
*/
|
|
46
|
+
nextFrame(): string;
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
/** Definition of spinner frame sets. */
|
|
@@ -60,7 +69,12 @@ export class Spinner extends SpinnerBase {
|
|
|
60
69
|
*/
|
|
61
70
|
constructor(spinnerDefinition?: SpinnerDefinition, isStarted?: boolean);
|
|
62
71
|
|
|
63
|
-
/**
|
|
72
|
+
/** Advances frame index for the active state-array (frames / notStarted / finished).
|
|
73
|
+
* No-op in `paused` state. Read-only-call `getFrame()` after.
|
|
74
|
+
* @returns This instance.
|
|
75
|
+
*/
|
|
76
|
+
tick(): this;
|
|
77
|
+
/** Returns the frame string at the current index for the active state-array. Read-only.
|
|
64
78
|
* @returns The frame string.
|
|
65
79
|
*/
|
|
66
80
|
getFrame(): string;
|
package/src/spinner/spinner.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import {checkMarkHeavy} from '../symbols.js';
|
|
2
2
|
|
|
3
|
-
/** Base class for spinners. Manages spinner state (active, paused, finished) and frame index. */
|
|
4
3
|
export class SpinnerBase {
|
|
5
|
-
/**
|
|
6
|
-
* @param {boolean} [isStarted=false] - Whether the spinner starts in the active state.
|
|
7
|
-
*/
|
|
8
4
|
constructor(isStarted) {
|
|
9
5
|
this.active = isStarted;
|
|
10
6
|
this.paused = false;
|
|
@@ -12,31 +8,24 @@ export class SpinnerBase {
|
|
|
12
8
|
this.frameIndex = 0;
|
|
13
9
|
}
|
|
14
10
|
|
|
15
|
-
/** Whether the spinner has been started (active or finished). */
|
|
16
11
|
get isStarted() {
|
|
17
12
|
return this.active || this.finished;
|
|
18
13
|
}
|
|
19
14
|
|
|
20
|
-
/** Whether the spinner is currently active. */
|
|
21
15
|
get isActive() {
|
|
22
16
|
return this.active;
|
|
23
17
|
}
|
|
24
18
|
|
|
25
|
-
/** Whether the spinner has finished. */
|
|
26
19
|
get isFinished() {
|
|
27
20
|
return this.finished;
|
|
28
21
|
}
|
|
29
22
|
|
|
30
|
-
/** The current state: `''`, `'active'`, `'paused'`, or `'finished'`. */
|
|
31
23
|
get state() {
|
|
32
24
|
if (this.finished) return 'finished';
|
|
33
25
|
if (this.active) return this.paused ? 'paused' : 'active';
|
|
34
26
|
return '';
|
|
35
27
|
}
|
|
36
28
|
|
|
37
|
-
/** Sets the spinner state.
|
|
38
|
-
* @param {''|'active'|'paused'|'finished'} value
|
|
39
|
-
*/
|
|
40
29
|
set state(value) {
|
|
41
30
|
this.finished = this.active = this.paused = false;
|
|
42
31
|
switch (value) {
|
|
@@ -52,51 +41,50 @@ export class SpinnerBase {
|
|
|
52
41
|
}
|
|
53
42
|
}
|
|
54
43
|
|
|
55
|
-
/** Resets the spinner to its initial (not started) state. */
|
|
56
44
|
reset() {
|
|
57
45
|
this.active = this.paused = this.finished = false;
|
|
58
46
|
}
|
|
59
47
|
|
|
60
|
-
/** Advances and returns the next frame index.
|
|
61
|
-
* @param {number} length - The total number of frames.
|
|
62
|
-
* @returns {number} The new frame index.
|
|
63
|
-
*/
|
|
64
48
|
nextFrameIndex(length) {
|
|
65
49
|
return (this.frameIndex = (this.frameIndex + 1) % length);
|
|
66
50
|
}
|
|
67
51
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
52
|
+
tick() {
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
|
|
71
56
|
getFrame() {
|
|
72
57
|
return 'X';
|
|
73
58
|
}
|
|
59
|
+
|
|
60
|
+
nextFrame() {
|
|
61
|
+
this.tick();
|
|
62
|
+
return this.getFrame();
|
|
63
|
+
}
|
|
74
64
|
}
|
|
75
65
|
|
|
76
66
|
const defaultSpinnerDefinition = {notStarted: [' '], finished: [checkMarkHeavy], frames: [...'⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏']};
|
|
77
67
|
|
|
78
|
-
/** A spinner with configurable frame sets for active, not-started, and finished states. */
|
|
79
68
|
export class Spinner extends SpinnerBase {
|
|
80
|
-
/**
|
|
81
|
-
* @param {object} [spinnerDefinition] - Spinner definition with `frames`, `notStarted`, and `finished` arrays.
|
|
82
|
-
* @param {string[]} [spinnerDefinition.frames] - Animation frames for the active state.
|
|
83
|
-
* @param {string[]} [spinnerDefinition.notStarted] - Frames shown before the spinner starts.
|
|
84
|
-
* @param {string[]} [spinnerDefinition.finished] - Frames shown after the spinner finishes.
|
|
85
|
-
* @param {boolean} [isStarted=false] - Whether the spinner starts active.
|
|
86
|
-
*/
|
|
87
69
|
constructor(spinnerDefinition, isStarted) {
|
|
88
70
|
super(isStarted);
|
|
89
71
|
this.spinner = {...defaultSpinnerDefinition, ...spinnerDefinition};
|
|
90
72
|
}
|
|
91
73
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
74
|
+
tick() {
|
|
75
|
+
if (this.finished) {
|
|
76
|
+
this.nextFrameIndex(this.spinner.finished.length);
|
|
77
|
+
} else if (!this.active) {
|
|
78
|
+
this.nextFrameIndex(this.spinner.notStarted.length);
|
|
79
|
+
} else if (!this.paused) {
|
|
80
|
+
this.nextFrameIndex(this.spinner.frames.length);
|
|
81
|
+
}
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
|
|
95
85
|
getFrame() {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (!this.paused) this.nextFrameIndex(this.spinner.frames.length);
|
|
99
|
-
return this.spinner.frames[this.frameIndex];
|
|
86
|
+
const arr = this.finished ? this.spinner.finished : !this.active ? this.spinner.notStarted : this.spinner.frames;
|
|
87
|
+
return arr[this.frameIndex % arr.length];
|
|
100
88
|
}
|
|
101
89
|
}
|
|
102
90
|
|
package/src/spinner/spinners.js
CHANGED
|
@@ -2,41 +2,26 @@
|
|
|
2
2
|
// Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
|
|
3
3
|
// See `cli-spinners` for more great options.
|
|
4
4
|
|
|
5
|
-
/** Braille dots spinner. */
|
|
6
5
|
export const dots = {frames: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']};
|
|
7
|
-
/** Sand/hourglass spinner. */
|
|
8
6
|
export const sand = {frames: [...'⠁⠂⠄⡀⡈⡐⡠⣀⣁⣂⣄⣌⣔⣤⣥⣦⣮⣶⣷⣿⡿⠿⢟⠟⡛⠛⠫⢋⠋⠍⡉⠉⠑⠡⢁']};
|
|
9
|
-
/** Line spinner (|/-\). */
|
|
10
7
|
export const line = {frames: ['-', '\\', '|', '/']};
|
|
11
|
-
/** Pipe spinner. */
|
|
12
8
|
export const pipe = {frames: ['┤', '┘', '┴', '└', '├', '┌', '┬', '┐']};
|
|
13
|
-
/** Vertical growing bar spinner. */
|
|
14
9
|
export const growVertical = {frames: ['▁', '▃', '▄', '▅', '▆', '▇', '▆', '▅', '▄', '▃']};
|
|
15
|
-
/** Horizontal growing bar spinner. */
|
|
16
10
|
export const growHorizontal = {frames: ['▏', '▎', '▍', '▌', '▋', '▊', '▉', '▊', '▋', '▌', '▍', '▎']};
|
|
17
|
-
/** Random noise spinner. */
|
|
18
11
|
export const noise = {frames: ['▓', '▒', '░']};
|
|
19
|
-
/** Bouncing spinner. */
|
|
20
12
|
export const bounce = {frames: ['⠁', '⠂', '⠄', '⠂']};
|
|
21
|
-
/** Arc spinner. */
|
|
22
13
|
export const arc = {frames: ['◜', '◠', '◝', '◞', '◡', '◟']};
|
|
23
|
-
/** Square quarters spinner. */
|
|
24
14
|
export const squareQuarters = {frames: ['◰', '◳', '◲', '◱']};
|
|
25
|
-
/** Circle quarters spinner. */
|
|
26
15
|
export const circleQuarters = {frames: ['◴', '◷', '◶', '◵']};
|
|
27
|
-
/** Circle halves spinner. */
|
|
28
16
|
export const circleHalves = {frames: ['◐', '◓', '◑', '◒']};
|
|
29
|
-
/** Arrows spinner. */
|
|
30
17
|
export const arrows = {frames: ['←', '↖', '↑', '↗', '→', '↘', '↓', '↙']};
|
|
31
18
|
|
|
32
|
-
/** Clock spinner. */
|
|
33
19
|
export const clock = {
|
|
34
20
|
frames: ['🕛 ', '🕐 ', '🕑 ', '🕒 ', '🕓 ', '🕔 ', '🕕 ', '🕖 ', '🕗 ', '🕘 ', '🕙 ', '🕚 '],
|
|
35
21
|
notStarted: [' '],
|
|
36
22
|
finished: ['✔ ']
|
|
37
23
|
};
|
|
38
24
|
|
|
39
|
-
/** Bouncing bar spinner. */
|
|
40
25
|
export const bouncingBar = {
|
|
41
26
|
frames: [
|
|
42
27
|
'[ ]',
|
|
@@ -60,7 +45,6 @@ export const bouncingBar = {
|
|
|
60
45
|
finished: ['[####]']
|
|
61
46
|
};
|
|
62
47
|
|
|
63
|
-
/** Bouncing ball spinner. */
|
|
64
48
|
export const bouncingBall = {
|
|
65
49
|
frames: [
|
|
66
50
|
'( ● )',
|
package/src/strings/clip.js
CHANGED
|
@@ -1,16 +1,6 @@
|
|
|
1
1
|
import parse, {matchCsiNoGroups} from './parse.js';
|
|
2
2
|
import {split} from './split.js';
|
|
3
3
|
|
|
4
|
-
/** Clips a string to a specified display width, correctly handling ANSI escape codes and multi-width characters.
|
|
5
|
-
* @param {string} s - The string to clip.
|
|
6
|
-
* @param {number} width - The maximum display width.
|
|
7
|
-
* @param {object} [options] - Options.
|
|
8
|
-
* @param {boolean} [options.includeLastCommand=false] - If true, include the last (invisible) ANSI command in the clipped result.
|
|
9
|
-
* @param {RegExp} [options.matcher=matchCsiNoGroups] - The regular expression used to match escape sequences.
|
|
10
|
-
* @param {boolean} [options.ignoreControlSymbols] - If true, control symbols are ignored during width calculation.
|
|
11
|
-
* @param {boolean} [options.ambiguousAsWide] - If true, ambiguous East Asian characters are treated as double-wide.
|
|
12
|
-
* @returns {string} The clipped string.
|
|
13
|
-
*/
|
|
14
4
|
export const clip = (s, width, options = {}) => {
|
|
15
5
|
const {includeLastCommand = false, matcher = matchCsiNoGroups} = options;
|
|
16
6
|
|
package/src/strings/parse.js
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
/** RegExp that matches CSI sequences with no capture groups. */
|
|
2
1
|
export const matchCsiNoGroups = /\x1B\[[\x30-\x3F]*[\x20-\x2F]*[\x40-\x7E]/g;
|
|
3
|
-
/** RegExp that matches CSI sequences excluding SGR commands, with no capture groups. */
|
|
4
2
|
export const matchCsiNoSgrNoGroups = /\x1B\[[\x30-\x3F]*[\x20-\x2F]*[\x40-\x6C\x6E-\x7E]/g;
|
|
5
3
|
|
|
6
|
-
/** Parses a string yielding segments of text and matched ANSI escape sequences.
|
|
7
|
-
* @param {string} s - The string to parse.
|
|
8
|
-
* @param {RegExp} [matcher=matchCsiNoGroups] - The regular expression used to match escape sequences.
|
|
9
|
-
* @yields {{start: number, string: string, match: RegExpMatchArray | null}} Parsed segments.
|
|
10
|
-
*/
|
|
11
4
|
export function* parse(s, matcher = matchCsiNoGroups) {
|
|
12
5
|
s = String(s);
|
|
13
6
|
let start = 0;
|