|
/** terminal utilities */ |
|
export const term = { |
|
clearLine: () => process.stdout.write("\r\x1b[K"), |
|
hideCursor: () => process.stdout.write("\x1b[?25l"), |
|
showCursor: () => process.stdout.write("\x1b[?25h"), |
|
}; |
|
|
|
/** |
|
* show a text spinner while `fn` is running |
|
* |
|
* @example |
|
* ```ts |
|
* const obj = spinner("thinking ", "simpleDots"); |
|
* const text = await fn(); |
|
* obj.stop(); |
|
* ``` |
|
* |
|
* @param text the text to be printed before the spinner |
|
* @param sequence the name of the spinner sequence, or an array of strings to be used as the spinner |
|
* @returns an object with a `stop` method |
|
*/ |
|
export function spinner(text: string, sequence?: SpinnersKey | string[]) { |
|
let spinnerChars = typeof sequence === "string" ? getSpinner(sequence) : sequence; |
|
if (!spinnerChars) { |
|
spinnerChars = spinners.simpleDots; |
|
} |
|
let i = 0; |
|
const spin = () => { |
|
const spinner = spinnerChars![i]; |
|
i = (i + 1) % spinnerChars!.length; |
|
return spinner; |
|
}; |
|
const stop = (text?: string) => { |
|
term.clearLine(); |
|
term.showCursor(); |
|
if (text) { |
|
process.stdout.write(text); |
|
} |
|
}; |
|
term.hideCursor(); |
|
process.stdout.write(text); |
|
const interval = setInterval(() => process.stdout.write("\r" + text + spin()), 100); |
|
return { |
|
/** stop the spinner and clear the line */ |
|
stop: (text?: string) => { |
|
clearInterval(interval); |
|
stop(text); |
|
}, |
|
}; |
|
} |
|
|
|
export type Spinners = typeof spinners; |
|
export type SpinnersKey = keyof Spinners; |
|
|
|
export function getSpinner(name: SpinnersKey) { |
|
return typeof name === "string" ? spinners[name] : name; |
|
} |
|
|
|
/** @see https://wiki.tcl-lang.org/page/Text+Spinner */ |
|
const spinners = { |
|
dots: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"], |
|
line: ["-", "\\", "|", "/"], |
|
line2: ["⠂", "-", "–", "—", "–", "-"], |
|
pipe: ["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"], |
|
simpleDots: [". ", ".. ", "...", " "], |
|
simpleDotsScrolling: [". ", ".. ", "...", " ..", " .", " "], |
|
star: ["✶", "✸", "✹", "✺", "✹", "✷"], |
|
star2: ["+", "x", "*"], |
|
flip: ["_", "_", "_", "-", "`", "`", "'", "´", "-", "_", "_", "_"], |
|
hamburger: ["☱", "☲", "☴"], |
|
growVertical: ["▁", "▃", "▄", "▅", "▆", "▇", "▆", "▅", "▄", "▃"], |
|
growHorizontal: ["▏", "▎", "▍", "▌", "▋", "▊", "▉", "▊", "▋", "▌", "▍", "▎"], |
|
balloon: [" ", ".", "o", "O", "@", "*", " ", " ", " ", " ", " "], |
|
balloon2: [".", "o", "O", "°", "O", "o", "."], |
|
noise: ["▓", "▒", "░"], |
|
bounce: ["⠁", "⠂", "⠄", "⠂"], |
|
boxBounce: ["▖", "▘", "▝", "▗"], |
|
boxBounce2: ["▌", "▀", "▐", "▄"], |
|
triangle: ["◢", "◣", "◤", "◥"], |
|
arc: ["◜", "◠", "◝", "◞", "◡", "◟"], |
|
circle: ["◡", "⊙", "◠"], |
|
squareCorners: ["◰", "◳", "◲", "◱"], |
|
circleQuarters: ["◴", "◷", "◶", "◵"], |
|
circleHalves: ["◐", "◓", "◑", "◒"], |
|
squish: ["╫", "╪"], |
|
toggle: ["⊶", "⊷"], |
|
toggle2: ["□", "■"], |
|
arrow: ["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"], |
|
arrow2: ["▹▹▹▹▹", "▸▹▹▹▹", "▹▸▹▹▹", "▹▹▸▹▹", "▹▹▹▸▹", "▹▹▹▹▸"], |
|
bird: ["︷", "︵", "︹", "︺", "︶", "︸", "︶", "︺", "︹", "︵"], |
|
bouncingBar: [ |
|
"[ ]", |
|
"[= ]", |
|
"[== ]", |
|
"[=== ]", |
|
"[ ===]", |
|
"[ ==]", |
|
"[ =]", |
|
"[ ]", |
|
"[ =]", |
|
"[ ==]", |
|
"[ ===]", |
|
"[====]", |
|
"[=== ]", |
|
"[== ]", |
|
"[= ]", |
|
], |
|
bouncingBall: [ |
|
"( ● )", |
|
"( ● )", |
|
"( ● )", |
|
"( ● )", |
|
"( ●)", |
|
"( ● )", |
|
"( ● )", |
|
"( ● )", |
|
"( ● )", |
|
"(● )", |
|
], |
|
pong: [ |
|
"▐● ▌", |
|
"▐ ● ▌", |
|
"▐ ● ▌", |
|
"▐ ● ▌", |
|
"▐ ● ▌", |
|
"▐ ● ▌", |
|
"▐ ● ▌", |
|
"▐ ●▌", |
|
"▐ ● ▌", |
|
"▐ ● ▌", |
|
"▐ ● ▌", |
|
"▐ ● ▌", |
|
"▐ ● ▌", |
|
"▐ ● ▌", |
|
], |
|
shark: [ |
|
"◣˷˷˷˷˷˷˷˷˷˷˷˷", |
|
"˷◣˷˷˷˷˷˷˷˷˷˷˷", |
|
"˷˷◣˷˷˷˷˷˷˷˷˷˷", |
|
"˷˷˷◣˷˷˷˷˷˷˷˷˷", |
|
"˷˷˷˷◣˷˷˷˷˷˷˷˷", |
|
"˷˷˷˷˷◣˷˷˷˷˷˷˷", |
|
"˷˷˷˷˷˷◣˷˷˷˷˷˷", |
|
"˷˷˷˷˷˷˷◣˷˷˷˷˷", |
|
"˷˷˷˷˷˷˷˷◣˷˷˷˷", |
|
"˷˷˷˷˷˷˷˷˷◣˷˷˷", |
|
"˷˷˷˷˷˷˷˷˷˷◣˷˷", |
|
"˷˷˷˷˷˷˷˷˷˷˷◣˷", |
|
"˷˷˷˷˷˷˷˷˷˷˷˷◣", |
|
"˷˷˷˷˷˷˷˷˷˷˷˷◢", |
|
"˷˷˷˷˷˷˷˷˷˷˷◢˷", |
|
"˷˷˷˷˷˷˷˷˷˷◢˷˷", |
|
"˷˷˷˷˷˷˷˷˷◢˷˷˷", |
|
"˷˷˷˷˷˷˷˷◢˷˷˷˷", |
|
"˷˷˷˷˷˷˷◢˷˷˷˷˷", |
|
"˷˷˷˷˷˷◢˷˷˷˷˷˷", |
|
"˷˷˷˷˷◢˷˷˷˷˷˷˷", |
|
"˷˷˷˷◢˷˷˷˷˷˷˷˷", |
|
"˷˷˷◢˷˷˷˷˷˷˷˷˷", |
|
"˷˷◢˷˷˷˷˷˷˷˷˷˷", |
|
"˷◢˷˷˷˷˷˷˷˷˷˷˷", |
|
"◢˷˷˷˷˷˷˷˷˷˷˷˷", |
|
], |
|
dqpb: ["d", "q", "p", "b"], |
|
grenade: [ |
|
"، ", |
|
"′ ", |
|
" ´ ", |
|
" ‾ ", |
|
" ⸌", |
|
" ⸊", |
|
" |", |
|
" ⁎", |
|
" ⁕", |
|
" ෴ ", |
|
" ⁓", |
|
" ", |
|
" ", |
|
" ", |
|
], |
|
point: ["∙∙∙", "●∙∙", "∙●∙", "∙∙●", "∙∙∙"], |
|
pointBounce: ["●∙∙∙∙", "∙●∙∙∙", "∙∙●∙∙", "∙∙∙●∙", "∙∙∙∙●", "∙∙∙●∙", "∙∙●∙∙", "∙●∙∙∙"], |
|
layer: ["-", "=", "≡"], |
|
betaWave: ["ρββββββ", "βρβββββ", "ββρββββ", "βββρβββ", "ββββρββ", "βββββρβ", "ββββββρ"], |
|
}; |
|
|
|
// handle ctrl+c - show the cursor and exit |
|
process.on("SIGINT", () => { |
|
term.showCursor(); |
|
process.stdout.write("\n"); |
|
process.exit(130); |
|
}); |