ui.ts 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { z } from "zod"
  2. import { EOL } from "os"
  3. import { NamedError } from "../util/error"
  4. // @ts-ignore
  5. import cliMarkdown from "cli-markdown"
  6. export namespace UI {
  7. const LOGO = [
  8. [`█▀▀█ █▀▀█ █▀▀ █▀▀▄ `, `█▀▀ █▀▀█ █▀▀▄ █▀▀`],
  9. [`█░░█ █░░█ █▀▀ █░░█ `, `█░░ █░░█ █░░█ █▀▀`],
  10. [`▀▀▀▀ █▀▀▀ ▀▀▀ ▀ ▀ `, `▀▀▀ ▀▀▀▀ ▀▀▀ ▀▀▀`],
  11. ]
  12. export const CancelledError = NamedError.create("UICancelledError", z.void())
  13. export const Style = {
  14. TEXT_HIGHLIGHT: "\x1b[96m",
  15. TEXT_HIGHLIGHT_BOLD: "\x1b[96m\x1b[1m",
  16. TEXT_DIM: "\x1b[90m",
  17. TEXT_DIM_BOLD: "\x1b[90m\x1b[1m",
  18. TEXT_NORMAL: "\x1b[0m",
  19. TEXT_NORMAL_BOLD: "\x1b[1m",
  20. TEXT_WARNING: "\x1b[93m",
  21. TEXT_WARNING_BOLD: "\x1b[93m\x1b[1m",
  22. TEXT_DANGER: "\x1b[91m",
  23. TEXT_DANGER_BOLD: "\x1b[91m\x1b[1m",
  24. TEXT_SUCCESS: "\x1b[92m",
  25. TEXT_SUCCESS_BOLD: "\x1b[92m\x1b[1m",
  26. TEXT_INFO: "\x1b[94m",
  27. TEXT_INFO_BOLD: "\x1b[94m\x1b[1m",
  28. }
  29. export function println(...message: string[]) {
  30. print(...message)
  31. Bun.stderr.write(EOL)
  32. }
  33. export function print(...message: string[]) {
  34. blank = false
  35. Bun.stderr.write(message.join(" "))
  36. }
  37. let blank = false
  38. export function empty() {
  39. if (blank) return
  40. println("" + Style.TEXT_NORMAL)
  41. blank = true
  42. }
  43. export function logo(pad?: string) {
  44. const result = []
  45. for (const row of LOGO) {
  46. if (pad) result.push(pad)
  47. result.push(Bun.color("gray", "ansi"))
  48. result.push(row[0])
  49. result.push("\x1b[0m")
  50. result.push(row[1])
  51. result.push(EOL)
  52. }
  53. return result.join("").trimEnd()
  54. }
  55. export async function input(prompt: string): Promise<string> {
  56. const readline = require("readline")
  57. const rl = readline.createInterface({
  58. input: process.stdin,
  59. output: process.stdout,
  60. })
  61. return new Promise((resolve) => {
  62. rl.question(prompt, (answer: string) => {
  63. rl.close()
  64. resolve(answer.trim())
  65. })
  66. })
  67. }
  68. export function error(message: string) {
  69. println(Style.TEXT_DANGER_BOLD + "Error: " + Style.TEXT_NORMAL + message)
  70. }
  71. export function markdown(text: string): string {
  72. const rendered = cliMarkdown(text, {
  73. width: process.stdout.columns || 80,
  74. firstHeading: false,
  75. tab: 0,
  76. }).trim()
  77. // Remove leading space from each line
  78. return rendered
  79. .split("\n")
  80. .map((line: string) => line.replace(/^ /, ""))
  81. .join("\n")
  82. }
  83. }