UNPKG

@travetto/terminal

Version:

General terminal support

43 lines (37 loc) 1.86 kB
import { StyleUtil, TermStyleFn, TermStyleInput } from './style.ts'; import { Terminal, WAIT_TOKEN } from './terminal.ts'; type ProgressEvent<T> = { total?: number, idx: number, value: T }; type ProgressStyle = { complete: TermStyleFn, incomplete?: TermStyleFn }; export class TerminalUtil { /** * Create a progress bar updater, suitable for streaming to the bottom of the screen */ static progressBarUpdater( term: Terminal, cfg?: { withWaiting?: boolean; style?: { complete: TermStyleInput, incomplete?: TermStyleInput } | (() => ProgressStyle); } ): (ev: ProgressEvent<string>) => string { const styleBase = typeof cfg?.style !== 'function' ? { complete: StyleUtil.getStyle(cfg?.style?.complete ?? { background: '#248613', text: '#ffffff' }), incomplete: cfg?.style?.incomplete ? StyleUtil.getStyle(cfg.style.incomplete) : undefined, } : undefined; const style = typeof cfg?.style === 'function' ? cfg.style : (): ProgressStyle => styleBase!; let width: number; return ev => { const text = ev.value ?? (ev.total ? '%idx/%total' : '%idx'); const pct = ev.total === undefined ? 0 : (ev.idx / ev.total); if (ev.total) { width ??= Math.trunc(Math.ceil(Math.log10(ev.total ?? 10000))); } const state: Record<string, string> = { total: `${ev.total}`, idx: `${ev.idx}`.padStart(width ?? 0), pct: `${Math.trunc(pct * 100)}` }; const line = ` ${text.replace(/[%](idx|total|pct)/g, (_, k) => state[k])} `; const full = term.writer.padToWidth(line, cfg?.withWaiting ? 2 : 0); const mid = Math.trunc(pct * term.width); const [l, r] = [full.substring(0, mid), full.substring(mid)]; const { complete, incomplete } = style(); return `${cfg?.withWaiting ? `${WAIT_TOKEN} ` : ''}${complete(l)}${incomplete?.(r) ?? r}`; }; } }