import charm = require ( "charm" ) ; export interface Options { /** Text to display in front of the progress bar. */ name : string ; /** Length of the progress bar. */ width ? : number ; /** Only render an update if this many milliseconds have passed. */ updateMinTime ? : number ; } export default class ProgressBar { private readonly console = new UpdatableConsole ( ) ; private readonly name : string ; private readonly width : number ; private readonly updateMinTime : number ; /** Most recent flavor text. */ private flavor = "" ; private lastUpdateMillis = 0 ; constructor ( options ) { this . name = options . name ; this . width = options . width === undefined ? 20 : options . width ; this . updateMinTime = options . updateMinTime === undefined ? 250 : options . updateMinTime ; } update ( current , flavor ? ) { if ( flavor !== undefined ) { this . flavor = flavor ; } const now = + ( new Date ( ) ) ; const diff = now - this . lastUpdateMillis ; if ( diff > this . updateMinTime ) { this . lastUpdateMillis = now ; this . doUpdate ( current ) ; } } private doUpdate ( current ) { const nCellsFilled = Math . ceil ( this . width * Math . min ( 1 , Math . max ( 0 , current ) ) ) ; this . console . update ( c => { c . write ( this . name ) ; c . write ( " [" ) ; c . write ( "█" . repeat ( nCellsFilled ) ) ; if ( nCellsFilled < this . width ) { c . right ( this . width - nCellsFilled ) ; } c . write ( "]" ) ; if ( this . flavor . length ) { c . write ( ` ${ this . flavor }` ) ; } } ) ; } done ( ) { this . flavor = "Done!" ; this . doUpdate ( 1 ) ; this . console . end ( ) ; } } /** A mutable line of text on the console. */ class UpdatableConsole { private readonly charm = charm ( process . stdout ) ; update ( action ) { this . charm . push ( ) ; this . charm . erase ( "line" ) ; action ( this . charm ) ; this . charm . pop ( ) ; } end ( ) { this . charm . write ( "\n" ) ; this . charm . end ( ) ; } } const firstLetter = "a" . charCodeAt ( 0 ) ; const lastLetter = "z" . charCodeAt ( 0 ) ; const charWidth = lastLetter - firstLetter ; const strProgressTotal = charWidth * charWidth ; /** Tracks a string's progress through the alphabet. */ export function strProgress ( str ) { const x = charProgress ( str . charCodeAt ( 0 ) ) * charWidth + charProgress ( str . charCodeAt ( 1 ) ) ; return x / strProgressTotal ; function charProgress ( ch ) { if ( Number . isNaN ( ch ) || ch <= firstLetter ) { return 0 ; } if ( ch >= lastLetter ) { return charWidth ; } return ch - firstLetter ; } }