[READ-ONLY] Mirror of https://github.com/bombshell-dev/clack. Effortlessly build beautiful command-line apps bomb.sh/docs/clack/basics/getting-started/
cli command-line command-line-app node prompt prompts
5

Configure Feed

Select the types of activity you want to include in your feed.

fix: wrap spinner output (#359)

authored by

James Garbutt and committed by
GitHub
(Jul 25, 2025, 10:30 PM +0100) 282b39e6 d4de920c

+341 -139
+5
.changeset/dull-singers-mate.md
··· 1 + --- 2 + "@clack/prompts": patch 3 + --- 4 + 5 + Wrap spinner output to allow for multi-line/wrapped messages.
+2 -1
packages/prompts/package.json
··· 61 61 "is-unicode-supported": "^1.3.0", 62 62 "memfs": "^4.17.2", 63 63 "vitest": "^3.2.4", 64 - "vitest-ansi-serializer": "^0.1.2" 64 + "vitest-ansi-serializer": "^0.1.2", 65 + "wrap-ansi": "^8.1.0" 65 66 } 66 67 }
+21 -7
packages/prompts/src/spinner.ts
··· 1 - import { block, settings } from '@clack/core'; 1 + import { block, getColumns, settings } from '@clack/core'; 2 2 import color from 'picocolors'; 3 3 import { cursor, erase } from 'sisteransi'; 4 + import wrap from 'wrap-ansi'; 4 5 import { 5 6 type CommonOptions, 6 7 isCI as isCIFn, ··· 46 47 let _message = ''; 47 48 let _prevMessage: string | undefined; 48 49 let _origin: number = performance.now(); 50 + const columns = getColumns(output); 49 51 50 52 const handleExit = (code: number) => { 51 53 const msg = ··· 94 96 const clearPrevMessage = () => { 95 97 if (_prevMessage === undefined) return; 96 98 if (isCI) output.write('\n'); 97 - const prevLines = _prevMessage.split('\n'); 98 - output.write(cursor.move(-999, prevLines.length - 1)); 99 - output.write(erase.down(prevLines.length)); 99 + const wrapped = wrap(_prevMessage, columns, { 100 + hard: true, 101 + trim: false, 102 + }); 103 + const prevLines = wrapped.split('\n'); 104 + output.write(cursor.up(prevLines.length - 1)); 105 + output.write(cursor.to(0)); 106 + output.write(erase.down()); 100 107 }; 101 108 102 109 const removeTrailingDots = (msg: string): string => { ··· 126 133 clearPrevMessage(); 127 134 _prevMessage = _message; 128 135 const frame = color.magenta(frames[frameIndex]); 136 + let outputMessage: string; 129 137 130 138 if (isCI) { 131 - output.write(`${frame} ${_message}...`); 139 + outputMessage = `${frame} ${_message}...`; 132 140 } else if (indicator === 'timer') { 133 - output.write(`${frame} ${_message} ${formatTimer(_origin)}`); 141 + outputMessage = `${frame} ${_message} ${formatTimer(_origin)}`; 134 142 } else { 135 143 const loadingDots = '.'.repeat(Math.floor(indicatorTimer)).slice(0, 3); 136 - output.write(`${frame} ${_message}${loadingDots}`); 144 + outputMessage = `${frame} ${_message}${loadingDots}`; 137 145 } 146 + 147 + const wrapped = wrap(outputMessage, columns, { 148 + hard: true, 149 + trim: false, 150 + }); 151 + output.write(wrapped); 138 152 139 153 frameIndex = frameIndex + 1 < frames.length ? frameIndex + 1 : 0; 140 154 // indicator increase by 1 every 8 frames
+66 -33
packages/prompts/test/__snapshots__/progress-bar.test.ts.snap
··· 6 6 "│ 7 7 ", 8 8 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", 9 - "<cursor.backward count=999>", 9 + "<cursor.up count=0>", 10 + "<cursor.left count=1>", 10 11 "<erase.down>", 11 12 "◐ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ foo", 12 13 ] ··· 95 96 "│ 96 97 ", 97 98 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", 98 - "<cursor.backward count=999>", 99 + "<cursor.up count=0>", 100 + "<cursor.left count=1>", 99 101 "<erase.down>", 100 102 "◐ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", 101 - "<cursor.backward count=999>", 103 + "<cursor.up count=0>", 104 + "<cursor.left count=1>", 102 105 "<erase.down>", 103 106 "◓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", 104 - "<cursor.backward count=999>", 107 + "<cursor.up count=0>", 108 + "<cursor.left count=1>", 105 109 "<erase.down>", 106 110 "◑ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", 107 111 ] ··· 131 135 "│ 132 136 ", 133 137 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", 134 - "<cursor.backward count=999>", 138 + "<cursor.up count=0>", 139 + "<cursor.left count=1>", 135 140 "<erase.down>", 136 141 "■ 137 142 ", ··· 145 150 "│ 146 151 ", 147 152 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", 148 - "<cursor.backward count=999>", 153 + "<cursor.up count=0>", 154 + "<cursor.left count=1>", 149 155 "<erase.down>", 150 156 "▲ 151 157 ", ··· 159 165 "│ 160 166 ", 161 167 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", 162 - "<cursor.backward count=999>", 168 + "<cursor.up count=0>", 169 + "<cursor.left count=1>", 163 170 "<erase.down>", 164 171 "◇ foo 165 172 ", ··· 173 180 "│ 174 181 ", 175 182 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", 176 - "<cursor.backward count=999>", 183 + "<cursor.up count=0>", 184 + "<cursor.left count=1>", 177 185 "<erase.down>", 178 186 "◇ foo. 179 187 ", ··· 187 195 "│ 188 196 ", 189 197 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ", 190 - "<cursor.backward count=999>", 198 + "<cursor.up count=0>", 199 + "<cursor.left count=1>", 191 200 "<erase.down>", 192 201 "◇ 193 202 ", ··· 201 210 "│ 202 211 ", 203 212 "◒ ██████████ ", 204 - "<cursor.backward count=999>", 213 + "<cursor.up count=0>", 214 + "<cursor.left count=1>", 205 215 "<erase.down>", 206 216 "◐ ██████████ ", 207 - "<cursor.backward count=999>", 217 + "<cursor.up count=0>", 218 + "<cursor.left count=1>", 208 219 "<erase.down>", 209 220 "◓ ██████████ ", 210 - "<cursor.backward count=999>", 221 + "<cursor.up count=0>", 222 + "<cursor.left count=1>", 211 223 "<erase.down>", 212 224 "◑ ██████████ ", 213 - "<cursor.backward count=999>", 225 + "<cursor.up count=0>", 226 + "<cursor.left count=1>", 214 227 "<erase.down>", 215 228 "◇ 216 229 ", ··· 224 237 "│ 225 238 ", 226 239 "◒ ━━━━━━━━━━ ", 227 - "<cursor.backward count=999>", 240 + "<cursor.up count=0>", 241 + "<cursor.left count=1>", 228 242 "<erase.down>", 229 243 "◐ ━━━━━━━━━━ ", 230 - "<cursor.backward count=999>", 244 + "<cursor.up count=0>", 245 + "<cursor.left count=1>", 231 246 "<erase.down>", 232 247 "◓ ━━━━━━━━━━ ", 233 - "<cursor.backward count=999>", 248 + "<cursor.up count=0>", 249 + "<cursor.left count=1>", 234 250 "<erase.down>", 235 251 "◑ ━━━━━━━━━━ ", 236 - "<cursor.backward count=999>", 252 + "<cursor.up count=0>", 253 + "<cursor.left count=1>", 237 254 "<erase.down>", 238 255 "◇ 239 256 ", ··· 247 264 "│ 248 265 ", 249 266 "◒ ────────── ", 250 - "<cursor.backward count=999>", 267 + "<cursor.up count=0>", 268 + "<cursor.left count=1>", 251 269 "<erase.down>", 252 270 "◐ ────────── ", 253 - "<cursor.backward count=999>", 271 + "<cursor.up count=0>", 272 + "<cursor.left count=1>", 254 273 "<erase.down>", 255 274 "◓ ────────── ", 256 - "<cursor.backward count=999>", 275 + "<cursor.up count=0>", 276 + "<cursor.left count=1>", 257 277 "<erase.down>", 258 278 "◑ ────────── ", 259 - "<cursor.backward count=999>", 279 + "<cursor.up count=0>", 280 + "<cursor.left count=1>", 260 281 "<erase.down>", 261 282 "◇ 262 283 ", ··· 272 293 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", 273 294 " 274 295 ", 275 - "<cursor.backward count=999>", 296 + "<cursor.up count=0>", 297 + "<cursor.left count=1>", 276 298 "<erase.down>", 277 299 "◐ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ foo...", 278 300 ] ··· 390 412 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", 391 413 " 392 414 ", 393 - "<cursor.backward count=999>", 415 + "<cursor.up count=0>", 416 + "<cursor.left count=1>", 394 417 "<erase.down>", 395 418 "■ 396 419 ", ··· 406 429 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", 407 430 " 408 431 ", 409 - "<cursor.backward count=999>", 432 + "<cursor.up count=0>", 433 + "<cursor.left count=1>", 410 434 "<erase.down>", 411 435 "▲ 412 436 ", ··· 422 446 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", 423 447 " 424 448 ", 425 - "<cursor.backward count=999>", 449 + "<cursor.up count=0>", 450 + "<cursor.left count=1>", 426 451 "<erase.down>", 427 452 "◇ foo 428 453 ", ··· 438 463 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", 439 464 " 440 465 ", 441 - "<cursor.backward count=999>", 466 + "<cursor.up count=0>", 467 + "<cursor.left count=1>", 442 468 "<erase.down>", 443 469 "◇ foo. 444 470 ", ··· 454 480 "◒ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ...", 455 481 " 456 482 ", 457 - "<cursor.backward count=999>", 483 + "<cursor.up count=0>", 484 + "<cursor.left count=1>", 458 485 "<erase.down>", 459 486 "◇ 460 487 ", ··· 470 497 "◒ ██████████ ...", 471 498 " 472 499 ", 473 - "<cursor.backward count=999>", 500 + "<cursor.up count=0>", 501 + "<cursor.left count=1>", 474 502 "<erase.down>", 475 503 "◐ ██████████ ...", 476 504 " 477 505 ", 478 - "<cursor.backward count=999>", 506 + "<cursor.up count=0>", 507 + "<cursor.left count=1>", 479 508 "<erase.down>", 480 509 "◇ 481 510 ", ··· 491 520 "◒ ━━━━━━━━━━ ...", 492 521 " 493 522 ", 494 - "<cursor.backward count=999>", 523 + "<cursor.up count=0>", 524 + "<cursor.left count=1>", 495 525 "<erase.down>", 496 526 "◐ ━━━━━━━━━━ ...", 497 527 " 498 528 ", 499 - "<cursor.backward count=999>", 529 + "<cursor.up count=0>", 530 + "<cursor.left count=1>", 500 531 "<erase.down>", 501 532 "◇ 502 533 ", ··· 512 543 "◒ ────────── ...", 513 544 " 514 545 ", 515 - "<cursor.backward count=999>", 546 + "<cursor.up count=0>", 547 + "<cursor.left count=1>", 516 548 "<erase.down>", 517 549 "◐ ────────── ...", 518 550 " 519 551 ", 520 - "<cursor.backward count=999>", 552 + "<cursor.up count=0>", 553 + "<cursor.left count=1>", 521 554 "<erase.down>", 522 555 "◇ 523 556 ",
+230 -98
packages/prompts/test/__snapshots__/spinner.test.ts.snap
··· 17 17 "│ 18 18 ", 19 19 "◒ ", 20 - "<cursor.backward count=999>", 20 + "<cursor.up count=0>", 21 + "<cursor.left count=1>", 21 22 "<erase.down>", 22 23 "◐ ", 23 - "<cursor.backward count=999>", 24 + "<cursor.up count=0>", 25 + "<cursor.left count=1>", 24 26 "<erase.down>", 25 27 "◓ ", 26 - "<cursor.backward count=999>", 28 + "<cursor.up count=0>", 29 + "<cursor.left count=1>", 27 30 "<erase.down>", 28 31 "◑ ", 29 - "<cursor.backward count=999>", 32 + "<cursor.up count=0>", 33 + "<cursor.left count=1>", 30 34 "<erase.down>", 31 35 "◇ 32 36 ", ··· 40 44 "│ 41 45 ", 42 46 "🐴 ", 43 - "<cursor.backward count=999>", 47 + "<cursor.up count=0>", 48 + "<cursor.left count=1>", 44 49 "<erase.down>", 45 50 "🦋 ", 46 - "<cursor.backward count=999>", 51 + "<cursor.up count=0>", 52 + "<cursor.left count=1>", 47 53 "<erase.down>", 48 54 "🐙 ", 49 - "<cursor.backward count=999>", 55 + "<cursor.up count=0>", 56 + "<cursor.left count=1>", 50 57 "<erase.down>", 51 58 "🐶 ", 52 - "<cursor.backward count=999>", 59 + "<cursor.up count=0>", 60 + "<cursor.left count=1>", 53 61 "<erase.down>", 54 62 "◇ 55 63 ", ··· 63 71 "│ 64 72 ", 65 73 "0 ", 66 - "<cursor.backward count=999>", 74 + "<cursor.up count=0>", 75 + "<cursor.left count=1>", 67 76 "<erase.down>", 68 77 "1 ", 69 - "<cursor.backward count=999>", 78 + "<cursor.up count=0>", 79 + "<cursor.left count=1>", 70 80 "<erase.down>", 71 81 "2 ", 72 - "<cursor.backward count=999>", 82 + "<cursor.up count=0>", 83 + "<cursor.left count=1>", 73 84 "<erase.down>", 74 85 "3 ", 75 - "<cursor.backward count=999>", 86 + "<cursor.up count=0>", 87 + "<cursor.left count=1>", 76 88 "<erase.down>", 77 89 "4 ", 78 - "<cursor.backward count=999>", 90 + "<cursor.up count=0>", 91 + "<cursor.left count=1>", 79 92 "<erase.down>", 80 93 "5 ", 81 - "<cursor.backward count=999>", 94 + "<cursor.up count=0>", 95 + "<cursor.left count=1>", 82 96 "<erase.down>", 83 97 "6 ", 84 - "<cursor.backward count=999>", 98 + "<cursor.up count=0>", 99 + "<cursor.left count=1>", 85 100 "<erase.down>", 86 101 "7 ", 87 - "<cursor.backward count=999>", 102 + "<cursor.up count=0>", 103 + "<cursor.left count=1>", 88 104 "<erase.down>", 89 105 "8 .", 90 - "<cursor.backward count=999>", 106 + "<cursor.up count=0>", 107 + "<cursor.left count=1>", 91 108 "<erase.down>", 92 109 "9 .", 93 - "<cursor.backward count=999>", 110 + "<cursor.up count=0>", 111 + "<cursor.left count=1>", 94 112 "<erase.down>", 95 113 "0 .", 96 - "<cursor.backward count=999>", 114 + "<cursor.up count=0>", 115 + "<cursor.left count=1>", 97 116 "<erase.down>", 98 117 "1 .", 99 - "<cursor.backward count=999>", 118 + "<cursor.up count=0>", 119 + "<cursor.left count=1>", 100 120 "<erase.down>", 101 121 "2 .", 102 - "<cursor.backward count=999>", 122 + "<cursor.up count=0>", 123 + "<cursor.left count=1>", 103 124 "<erase.down>", 104 125 "3 .", 105 - "<cursor.backward count=999>", 126 + "<cursor.up count=0>", 127 + "<cursor.left count=1>", 106 128 "<erase.down>", 107 129 "4 .", 108 - "<cursor.backward count=999>", 130 + "<cursor.up count=0>", 131 + "<cursor.left count=1>", 109 132 "<erase.down>", 110 133 "5 .", 111 - "<cursor.backward count=999>", 134 + "<cursor.up count=0>", 135 + "<cursor.left count=1>", 112 136 "<erase.down>", 113 137 "6 ..", 114 - "<cursor.backward count=999>", 138 + "<cursor.up count=0>", 139 + "<cursor.left count=1>", 115 140 "<erase.down>", 116 141 "7 ..", 117 - "<cursor.backward count=999>", 142 + "<cursor.up count=0>", 143 + "<cursor.left count=1>", 118 144 "<erase.down>", 119 145 "8 ..", 120 - "<cursor.backward count=999>", 146 + "<cursor.up count=0>", 147 + "<cursor.left count=1>", 121 148 "<erase.down>", 122 149 "9 ..", 123 - "<cursor.backward count=999>", 150 + "<cursor.up count=0>", 151 + "<cursor.left count=1>", 124 152 "<erase.down>", 125 153 "0 ..", 126 - "<cursor.backward count=999>", 154 + "<cursor.up count=0>", 155 + "<cursor.left count=1>", 127 156 "<erase.down>", 128 157 "1 ..", 129 - "<cursor.backward count=999>", 158 + "<cursor.up count=0>", 159 + "<cursor.left count=1>", 130 160 "<erase.down>", 131 161 "2 ..", 132 - "<cursor.backward count=999>", 162 + "<cursor.up count=0>", 163 + "<cursor.left count=1>", 133 164 "<erase.down>", 134 165 "3 ..", 135 - "<cursor.backward count=999>", 166 + "<cursor.up count=0>", 167 + "<cursor.left count=1>", 136 168 "<erase.down>", 137 169 "4 ...", 138 - "<cursor.backward count=999>", 170 + "<cursor.up count=0>", 171 + "<cursor.left count=1>", 139 172 "<erase.down>", 140 173 "5 ...", 141 - "<cursor.backward count=999>", 174 + "<cursor.up count=0>", 175 + "<cursor.left count=1>", 142 176 "<erase.down>", 143 177 "6 ...", 144 - "<cursor.backward count=999>", 178 + "<cursor.up count=0>", 179 + "<cursor.left count=1>", 145 180 "<erase.down>", 146 181 "7 ...", 147 - "<cursor.backward count=999>", 182 + "<cursor.up count=0>", 183 + "<cursor.left count=1>", 148 184 "<erase.down>", 149 185 "8 ...", 150 - "<cursor.backward count=999>", 186 + "<cursor.up count=0>", 187 + "<cursor.left count=1>", 151 188 "<erase.down>", 152 189 "9 ...", 153 - "<cursor.backward count=999>", 190 + "<cursor.up count=0>", 191 + "<cursor.left count=1>", 154 192 "<erase.down>", 155 193 "0 ...", 156 - "<cursor.backward count=999>", 194 + "<cursor.up count=0>", 195 + "<cursor.left count=1>", 157 196 "<erase.down>", 158 197 "1 ...", 159 - "<cursor.backward count=999>", 198 + "<cursor.up count=0>", 199 + "<cursor.left count=1>", 160 200 "<erase.down>", 161 201 "2 ...", 162 - "<cursor.backward count=999>", 202 + "<cursor.up count=0>", 203 + "<cursor.left count=1>", 163 204 "<erase.down>", 164 205 "3 ", 165 - "<cursor.backward count=999>", 206 + "<cursor.up count=0>", 207 + "<cursor.left count=1>", 166 208 "<erase.down>", 167 209 "4 ", 168 - "<cursor.backward count=999>", 210 + "<cursor.up count=0>", 211 + "<cursor.left count=1>", 169 212 "<erase.down>", 170 213 "5 ", 171 - "<cursor.backward count=999>", 214 + "<cursor.up count=0>", 215 + "<cursor.left count=1>", 172 216 "<erase.down>", 173 217 "6 ", 174 - "<cursor.backward count=999>", 218 + "<cursor.up count=0>", 219 + "<cursor.left count=1>", 175 220 "<erase.down>", 176 221 "7 ", 177 - "<cursor.backward count=999>", 222 + "<cursor.up count=0>", 223 + "<cursor.left count=1>", 178 224 "<erase.down>", 179 225 "8 ", 180 - "<cursor.backward count=999>", 226 + "<cursor.up count=0>", 227 + "<cursor.left count=1>", 181 228 "<erase.down>", 182 229 "9 ", 183 - "<cursor.backward count=999>", 230 + "<cursor.up count=0>", 231 + "<cursor.left count=1>", 184 232 "<erase.down>", 185 233 "0 ", 186 - "<cursor.backward count=999>", 234 + "<cursor.up count=0>", 235 + "<cursor.left count=1>", 187 236 "<erase.down>", 188 237 "1 .", 189 - "<cursor.backward count=999>", 238 + "<cursor.up count=0>", 239 + "<cursor.left count=1>", 190 240 "<erase.down>", 191 241 "2 .", 192 - "<cursor.backward count=999>", 242 + "<cursor.up count=0>", 243 + "<cursor.left count=1>", 193 244 "<erase.down>", 194 245 "3 .", 195 - "<cursor.backward count=999>", 246 + "<cursor.up count=0>", 247 + "<cursor.left count=1>", 196 248 "<erase.down>", 197 249 "4 .", 198 - "<cursor.backward count=999>", 250 + "<cursor.up count=0>", 251 + "<cursor.left count=1>", 199 252 "<erase.down>", 200 253 "5 .", 201 - "<cursor.backward count=999>", 254 + "<cursor.up count=0>", 255 + "<cursor.left count=1>", 202 256 "<erase.down>", 203 257 "6 .", 204 - "<cursor.backward count=999>", 258 + "<cursor.up count=0>", 259 + "<cursor.left count=1>", 205 260 "<erase.down>", 206 261 "7 .", 207 - "<cursor.backward count=999>", 262 + "<cursor.up count=0>", 263 + "<cursor.left count=1>", 208 264 "<erase.down>", 209 265 "8 .", 210 - "<cursor.backward count=999>", 266 + "<cursor.up count=0>", 267 + "<cursor.left count=1>", 211 268 "<erase.down>", 212 269 "9 ..", 213 - "<cursor.backward count=999>", 270 + "<cursor.up count=0>", 271 + "<cursor.left count=1>", 214 272 "<erase.down>", 215 273 "0 ..", 216 - "<cursor.backward count=999>", 274 + "<cursor.up count=0>", 275 + "<cursor.left count=1>", 217 276 "<erase.down>", 218 277 "1 ..", 219 - "<cursor.backward count=999>", 278 + "<cursor.up count=0>", 279 + "<cursor.left count=1>", 220 280 "<erase.down>", 221 281 "2 ..", 222 - "<cursor.backward count=999>", 282 + "<cursor.up count=0>", 283 + "<cursor.left count=1>", 223 284 "<erase.down>", 224 285 "3 ..", 225 - "<cursor.backward count=999>", 286 + "<cursor.up count=0>", 287 + "<cursor.left count=1>", 226 288 "<erase.down>", 227 289 "4 ..", 228 - "<cursor.backward count=999>", 290 + "<cursor.up count=0>", 291 + "<cursor.left count=1>", 229 292 "<erase.down>", 230 293 "5 ..", 231 - "<cursor.backward count=999>", 294 + "<cursor.up count=0>", 295 + "<cursor.left count=1>", 232 296 "<erase.down>", 233 297 "6 ..", 234 - "<cursor.backward count=999>", 298 + "<cursor.up count=0>", 299 + "<cursor.left count=1>", 235 300 "<erase.down>", 236 301 "7 ...", 237 - "<cursor.backward count=999>", 302 + "<cursor.up count=0>", 303 + "<cursor.left count=1>", 238 304 "<erase.down>", 239 305 "8 ...", 240 - "<cursor.backward count=999>", 306 + "<cursor.up count=0>", 307 + "<cursor.left count=1>", 241 308 "<erase.down>", 242 309 "9 ...", 243 - "<cursor.backward count=999>", 310 + "<cursor.up count=0>", 311 + "<cursor.left count=1>", 244 312 "<erase.down>", 245 313 "0 ...", 246 - "<cursor.backward count=999>", 314 + "<cursor.up count=0>", 315 + "<cursor.left count=1>", 247 316 "<erase.down>", 248 317 "1 ...", 249 - "<cursor.backward count=999>", 318 + "<cursor.up count=0>", 319 + "<cursor.left count=1>", 250 320 "<erase.down>", 251 321 "2 ...", 252 - "<cursor.backward count=999>", 322 + "<cursor.up count=0>", 323 + "<cursor.left count=1>", 253 324 "<erase.down>", 254 325 "3 ...", 255 - "<cursor.backward count=999>", 326 + "<cursor.up count=0>", 327 + "<cursor.left count=1>", 256 328 "<erase.down>", 257 329 "◇ 258 330 ", ··· 266 338 "│ 267 339 ", 268 340 "◒ ", 269 - "<cursor.backward count=999>", 341 + "<cursor.up count=0>", 342 + "<cursor.left count=1>", 270 343 "<erase.down>", 271 344 "◐ foo", 272 - "<cursor.backward count=999>", 345 + "<cursor.up count=0>", 346 + "<cursor.left count=1>", 273 347 "<erase.down>", 274 348 "◇ 275 349 ", ··· 354 428 ] 355 429 `; 356 430 431 + exports[`spinner (isCI = false) > start > handles wrapping 1`] = ` 432 + [ 433 + "<cursor.hide>", 434 + "│ 435 + ", 436 + "◒ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 437 + xxxxxxxxxxxxx", 438 + "<cursor.up count=1>", 439 + "<cursor.left count=1>", 440 + "<erase.down>", 441 + "◇ stopped 442 + ", 443 + "<cursor.show>", 444 + ] 445 + `; 446 + 357 447 exports[`spinner (isCI = false) > start > renders frames at interval 1`] = ` 358 448 [ 359 449 "<cursor.hide>", 360 450 "│ 361 451 ", 362 452 "◒ ", 363 - "<cursor.backward count=999>", 453 + "<cursor.up count=0>", 454 + "<cursor.left count=1>", 364 455 "<erase.down>", 365 456 "◐ ", 366 - "<cursor.backward count=999>", 457 + "<cursor.up count=0>", 458 + "<cursor.left count=1>", 367 459 "<erase.down>", 368 460 "◓ ", 369 - "<cursor.backward count=999>", 461 + "<cursor.up count=0>", 462 + "<cursor.left count=1>", 370 463 "<erase.down>", 371 464 "◑ ", 372 - "<cursor.backward count=999>", 465 + "<cursor.up count=0>", 466 + "<cursor.left count=1>", 373 467 "<erase.down>", 374 468 "◇ 375 469 ", ··· 383 477 "│ 384 478 ", 385 479 "◒ foo", 386 - "<cursor.backward count=999>", 480 + "<cursor.up count=0>", 481 + "<cursor.left count=1>", 387 482 "<erase.down>", 388 483 "◇ 389 484 ", ··· 397 492 "│ 398 493 ", 399 494 "◒ [0s]", 400 - "<cursor.backward count=999>", 495 + "<cursor.up count=0>", 496 + "<cursor.left count=1>", 401 497 "<erase.down>", 402 498 "◇ [0s] 403 499 ", ··· 411 507 "│ 412 508 ", 413 509 "◒ ", 414 - "<cursor.backward count=999>", 510 + "<cursor.up count=0>", 511 + "<cursor.left count=1>", 415 512 "<erase.down>", 416 513 "■ 417 514 ", ··· 425 522 "│ 426 523 ", 427 524 "◒ ", 428 - "<cursor.backward count=999>", 525 + "<cursor.up count=0>", 526 + "<cursor.left count=1>", 429 527 "<erase.down>", 430 528 "▲ 431 529 ", ··· 439 537 "│ 440 538 ", 441 539 "◒ ", 442 - "<cursor.backward count=999>", 540 + "<cursor.up count=0>", 541 + "<cursor.left count=1>", 443 542 "<erase.down>", 444 543 "◇ foo 445 544 ", ··· 453 552 "│ 454 553 ", 455 554 "◒ ", 456 - "<cursor.backward count=999>", 555 + "<cursor.up count=0>", 556 + "<cursor.left count=1>", 457 557 "<erase.down>", 458 558 "◇ foo. 459 559 ", ··· 467 567 "│ 468 568 ", 469 569 "◒ ", 470 - "<cursor.backward count=999>", 570 + "<cursor.up count=0>", 571 + "<cursor.left count=1>", 471 572 "<erase.down>", 472 573 "◇ 473 574 ", ··· 494 595 "◒ ...", 495 596 " 496 597 ", 497 - "<cursor.backward count=999>", 598 + "<cursor.up count=0>", 599 + "<cursor.left count=1>", 498 600 "<erase.down>", 499 601 "◇ 500 602 ", ··· 510 612 "🐴 ...", 511 613 " 512 614 ", 513 - "<cursor.backward count=999>", 615 + "<cursor.up count=0>", 616 + "<cursor.left count=1>", 514 617 "<erase.down>", 515 618 "◇ 516 619 ", ··· 526 629 "0 ...", 527 630 " 528 631 ", 529 - "<cursor.backward count=999>", 632 + "<cursor.up count=0>", 633 + "<cursor.left count=1>", 530 634 "<erase.down>", 531 635 "◇ 532 636 ", ··· 542 646 "◒ ...", 543 647 " 544 648 ", 545 - "<cursor.backward count=999>", 649 + "<cursor.up count=0>", 650 + "<cursor.left count=1>", 546 651 "<erase.down>", 547 652 "◐ foo...", 548 653 " 549 654 ", 550 - "<cursor.backward count=999>", 655 + "<cursor.up count=0>", 656 + "<cursor.left count=1>", 551 657 "<erase.down>", 552 658 "◇ 553 659 ", ··· 632 738 ] 633 739 `; 634 740 741 + exports[`spinner (isCI = true) > start > handles wrapping 1`] = ` 742 + [ 743 + "<cursor.hide>", 744 + "│ 745 + ", 746 + "◒ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 747 + xxxxxxxxxxxxx...", 748 + " 749 + ", 750 + "<cursor.up count=1>", 751 + "<cursor.left count=1>", 752 + "<erase.down>", 753 + "◇ stopped 754 + ", 755 + "<cursor.show>", 756 + ] 757 + `; 758 + 635 759 exports[`spinner (isCI = true) > start > renders frames at interval 1`] = ` 636 760 [ 637 761 "<cursor.hide>", ··· 640 764 "◒ ...", 641 765 " 642 766 ", 643 - "<cursor.backward count=999>", 767 + "<cursor.up count=0>", 768 + "<cursor.left count=1>", 644 769 "<erase.down>", 645 770 "◇ 646 771 ", ··· 656 781 "◒ foo...", 657 782 " 658 783 ", 659 - "<cursor.backward count=999>", 784 + "<cursor.up count=0>", 785 + "<cursor.left count=1>", 660 786 "<erase.down>", 661 787 "◇ 662 788 ", ··· 672 798 "◒ ...", 673 799 " 674 800 ", 675 - "<cursor.backward count=999>", 801 + "<cursor.up count=0>", 802 + "<cursor.left count=1>", 676 803 "<erase.down>", 677 804 "◇ [0s] 678 805 ", ··· 688 815 "◒ ...", 689 816 " 690 817 ", 691 - "<cursor.backward count=999>", 818 + "<cursor.up count=0>", 819 + "<cursor.left count=1>", 692 820 "<erase.down>", 693 821 "■ 694 822 ", ··· 704 832 "◒ ...", 705 833 " 706 834 ", 707 - "<cursor.backward count=999>", 835 + "<cursor.up count=0>", 836 + "<cursor.left count=1>", 708 837 "<erase.down>", 709 838 "▲ 710 839 ", ··· 720 849 "◒ ...", 721 850 " 722 851 ", 723 - "<cursor.backward count=999>", 852 + "<cursor.up count=0>", 853 + "<cursor.left count=1>", 724 854 "<erase.down>", 725 855 "◇ foo 726 856 ", ··· 736 866 "◒ ...", 737 867 " 738 868 ", 739 - "<cursor.backward count=999>", 869 + "<cursor.up count=0>", 870 + "<cursor.left count=1>", 740 871 "<erase.down>", 741 872 "◇ foo. 742 873 ", ··· 752 883 "◒ ...", 753 884 " 754 885 ", 755 - "<cursor.backward count=999>", 886 + "<cursor.up count=0>", 887 + "<cursor.left count=1>", 756 888 "<erase.down>", 757 889 "◇ 758 890 ",
+14
packages/prompts/test/spinner.test.ts
··· 1 1 import { EventEmitter } from 'node:stream'; 2 + import { getColumns } from '@clack/core'; 2 3 import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, test, vi } from 'vitest'; 3 4 import * as prompts from '../src/index.js'; 4 5 import { MockWritable } from './test-utils.js'; ··· 70 71 vi.advanceTimersByTime(80); 71 72 72 73 result.stop(); 74 + 75 + expect(output.buffer).toMatchSnapshot(); 76 + }); 77 + 78 + test('handles wrapping', () => { 79 + const columns = getColumns(output); 80 + const result = prompts.spinner({ output }); 81 + 82 + result.start('x'.repeat(columns + 10)); 83 + 84 + vi.advanceTimersByTime(80); 85 + 86 + result.stop('stopped'); 73 87 74 88 expect(output.buffer).toMatchSnapshot(); 75 89 });
+3
pnpm-lock.yaml
··· 98 98 vitest-ansi-serializer: 99 99 specifier: ^0.1.2 100 100 version: 0.1.2(vitest@3.2.4(@types/node@24.1.0)(jiti@2.5.0)) 101 + wrap-ansi: 102 + specifier: ^8.1.0 103 + version: 8.1.0 101 104 102 105 packages: 103 106