[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(@clack/prompts): add `spinner` hook to handle process exit (#113)

authored by

Christian Preston and committed by
GitHub
(Aug 9, 2023, 12:55 PM EDT) 9ce1295b 1c61e1a6

+66 -34
+5
.changeset/ninety-ravens-smoke.md
··· 1 + --- 2 + '@clack/prompts': patch 3 + --- 4 + 5 + Fix `spinner` conflict with terminal on error between `spinner.start()` and `spinner.stop()`
+61 -34
packages/prompts/src/index.ts
··· 635 635 }, 636 636 }; 637 637 638 - const frames = unicode ? ['◒', '◐', '◓', '◑'] : ['•', 'o', 'O', '0']; 639 - 640 638 export const spinner = () => { 639 + const frames = unicode ? ['◒', '◐', '◓', '◑'] : ['•', 'o', 'O', '0']; 640 + const delay = unicode ? 80 : 120; 641 + 641 642 let unblock: () => void; 642 643 let loop: NodeJS.Timer; 643 - let message = ''; 644 - const delay = unicode ? 80 : 120; 644 + let isSpinnerActive: boolean = false; 645 + let _message: string = ''; 646 + 647 + const start = (msg: string = ''): void => { 648 + isSpinnerActive = true; 649 + unblock = block(); 650 + _message = msg.replace(/\.+$/, ''); 651 + process.stdout.write(`${color.gray(S_BAR)}\n`); 652 + let frameIndex = 0; 653 + let dotsTimer = 0; 654 + loop = setInterval(() => { 655 + const frame = color.magenta(frames[frameIndex]); 656 + const loadingDots = '.'.repeat(Math.floor(dotsTimer)).slice(0, 3); 657 + process.stdout.write(cursor.move(-999, 0)); 658 + process.stdout.write(erase.down(1)); 659 + process.stdout.write(`${frame} ${_message}${loadingDots}`); 660 + frameIndex = frameIndex + 1 < frames.length ? frameIndex + 1 : 0; 661 + dotsTimer = dotsTimer < frames.length ? dotsTimer + 0.125 : 0; 662 + }, delay); 663 + }; 664 + 665 + const stop = (msg: string = '', code: number = 0): void => { 666 + _message = msg ?? _message 667 + isSpinnerActive = false; 668 + clearInterval(loop); 669 + const step = 670 + code === 0 671 + ? color.green(S_STEP_SUBMIT) 672 + : code === 1 673 + ? color.red(S_STEP_CANCEL) 674 + : color.red(S_STEP_ERROR); 675 + process.stdout.write(cursor.move(-999, 0)); 676 + process.stdout.write(erase.down(1)); 677 + process.stdout.write(`${step} ${_message}\n`); 678 + unblock(); 679 + }; 680 + 681 + const message = (msg: string = ''): void => { 682 + _message = msg ?? _message; 683 + }; 684 + 685 + const handleExit = (code: number) => { 686 + const msg = code > 1 ? 'Something went wrong' : 'Canceled'; 687 + if (isSpinnerActive) stop(msg, code); 688 + }; 689 + 690 + // Reference: https://nodejs.org/api/process.html#event-uncaughtexception 691 + process.on('uncaughtExceptionMonitor', () => handleExit(2)); 692 + // Reference: https://nodejs.org/api/process.html#event-unhandledrejection 693 + process.on('unhandledRejection', () => handleExit(2)); 694 + // Reference Signal Events: https://nodejs.org/api/process.html#signal-events 695 + process.on('SIGINT', () => handleExit(1)); 696 + process.on('SIGTERM', () => handleExit(1)); 697 + process.on('exit', handleExit); 698 + 645 699 return { 646 - start(msg = '') { 647 - this.message(msg); 648 - message = message.replace(/\.?\.?\.$/, ''); 649 - unblock = block(); 650 - process.stdout.write(`${color.gray(S_BAR)}\n${color.magenta('○')} ${message}\n`); 651 - let i = 0; 652 - let dot = 0; 653 - loop = setInterval(() => { 654 - let frame = frames[i]; 655 - process.stdout.write(cursor.move(-999, -1)); 656 - process.stdout.write( 657 - `${color.magenta(frame)} ${message}${ 658 - Math.floor(dot) >= 1 ? '.'.repeat(Math.floor(dot)).slice(0, 3) : '' 659 - } \n` 660 - ); 661 - i = i === frames.length - 1 ? 0 : i + 1; 662 - dot = dot === frames.length ? 0 : dot + 0.125; 663 - }, delay); 664 - }, 665 - message(msg = '') { 666 - message = msg ?? message; 667 - }, 668 - stop(msg = '') { 669 - this.message(msg); 670 - process.stdout.write(cursor.move(-999, -2)); 671 - process.stdout.write(erase.down(2)); 672 - clearInterval(loop); 673 - process.stdout.write(`${color.gray(S_BAR)}\n${color.green(S_STEP_SUBMIT)} ${message}\n`); 674 - unblock(); 675 - }, 700 + start, 701 + stop, 702 + message, 676 703 }; 677 704 }; 678 705