You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					234 lines
				
				6.8 KiB
			
		
		
			
		
	
	
					234 lines
				
				6.8 KiB
			| 
											3 years ago
										 | 'use strict' | ||
|  | var Plumbing = require('./plumbing.js') | ||
|  | var hasUnicode = require('has-unicode') | ||
|  | var hasColor = require('./has-color.js') | ||
|  | var onExit = require('signal-exit') | ||
|  | var defaultThemes = require('./themes') | ||
|  | var setInterval = require('./set-interval.js') | ||
|  | var process = require('./process.js') | ||
|  | var setImmediate = require('./set-immediate') | ||
|  | 
 | ||
|  | module.exports = Gauge | ||
|  | 
 | ||
|  | function callWith (obj, method) { | ||
|  |   return function () { | ||
|  |     return method.call(obj) | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | function Gauge (arg1, arg2) { | ||
|  |   var options, writeTo | ||
|  |   if (arg1 && arg1.write) { | ||
|  |     writeTo = arg1 | ||
|  |     options = arg2 || {} | ||
|  |   } else if (arg2 && arg2.write) { | ||
|  |     writeTo = arg2 | ||
|  |     options = arg1 || {} | ||
|  |   } else { | ||
|  |     writeTo = process.stderr | ||
|  |     options = arg1 || arg2 || {} | ||
|  |   } | ||
|  | 
 | ||
|  |   this._status = { | ||
|  |     spun: 0, | ||
|  |     section: '', | ||
|  |     subsection: '' | ||
|  |   } | ||
|  |   this._paused = false // are we paused for back pressure?
 | ||
|  |   this._disabled = true // are all progress bar updates disabled?
 | ||
|  |   this._showing = false // do we WANT the progress bar on screen
 | ||
|  |   this._onScreen = false // IS the progress bar on screen
 | ||
|  |   this._needsRedraw = false // should we print something at next tick?
 | ||
|  |   this._hideCursor = options.hideCursor == null ? true : options.hideCursor | ||
|  |   this._fixedFramerate = options.fixedFramerate == null | ||
|  |     ? !(/^v0\.8\./.test(process.version)) | ||
|  |     : options.fixedFramerate | ||
|  |   this._lastUpdateAt = null | ||
|  |   this._updateInterval = options.updateInterval == null ? 50 : options.updateInterval | ||
|  | 
 | ||
|  |   this._themes = options.themes || defaultThemes | ||
|  |   this._theme = options.theme | ||
|  |   var theme = this._computeTheme(options.theme) | ||
|  |   var template = options.template || [ | ||
|  |     {type: 'progressbar', length: 20}, | ||
|  |     {type: 'activityIndicator', kerning: 1, length: 1}, | ||
|  |     {type: 'section', kerning: 1, default: ''}, | ||
|  |     {type: 'subsection', kerning: 1, default: ''} | ||
|  |   ] | ||
|  |   this.setWriteTo(writeTo, options.tty) | ||
|  |   var PlumbingClass = options.Plumbing || Plumbing | ||
|  |   this._gauge = new PlumbingClass(theme, template, this.getWidth()) | ||
|  | 
 | ||
|  |   this._$$doRedraw = callWith(this, this._doRedraw) | ||
|  |   this._$$handleSizeChange = callWith(this, this._handleSizeChange) | ||
|  | 
 | ||
|  |   this._cleanupOnExit = options.cleanupOnExit == null || options.cleanupOnExit | ||
|  |   this._removeOnExit = null | ||
|  | 
 | ||
|  |   if (options.enabled || (options.enabled == null && this._tty && this._tty.isTTY)) { | ||
|  |     this.enable() | ||
|  |   } else { | ||
|  |     this.disable() | ||
|  |   } | ||
|  | } | ||
|  | Gauge.prototype = {} | ||
|  | 
 | ||
|  | Gauge.prototype.isEnabled = function () { | ||
|  |   return !this._disabled | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype.setTemplate = function (template) { | ||
|  |   this._gauge.setTemplate(template) | ||
|  |   if (this._showing) this._requestRedraw() | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype._computeTheme = function (theme) { | ||
|  |   if (!theme) theme = {} | ||
|  |   if (typeof theme === 'string') { | ||
|  |     theme = this._themes.getTheme(theme) | ||
|  |   } else if (theme && (Object.keys(theme).length === 0 || theme.hasUnicode != null || theme.hasColor != null)) { | ||
|  |     var useUnicode = theme.hasUnicode == null ? hasUnicode() : theme.hasUnicode | ||
|  |     var useColor = theme.hasColor == null ? hasColor : theme.hasColor | ||
|  |     theme = this._themes.getDefault({hasUnicode: useUnicode, hasColor: useColor, platform: theme.platform}) | ||
|  |   } | ||
|  |   return theme | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype.setThemeset = function (themes) { | ||
|  |   this._themes = themes | ||
|  |   this.setTheme(this._theme) | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype.setTheme = function (theme) { | ||
|  |   this._gauge.setTheme(this._computeTheme(theme)) | ||
|  |   if (this._showing) this._requestRedraw() | ||
|  |   this._theme = theme | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype._requestRedraw = function () { | ||
|  |   this._needsRedraw = true | ||
|  |   if (!this._fixedFramerate) this._doRedraw() | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype.getWidth = function () { | ||
|  |   return ((this._tty && this._tty.columns) || 80) - 1 | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype.setWriteTo = function (writeTo, tty) { | ||
|  |   var enabled = !this._disabled | ||
|  |   if (enabled) this.disable() | ||
|  |   this._writeTo = writeTo | ||
|  |   this._tty = tty || | ||
|  |     (writeTo === process.stderr && process.stdout.isTTY && process.stdout) || | ||
|  |     (writeTo.isTTY && writeTo) || | ||
|  |     this._tty | ||
|  |   if (this._gauge) this._gauge.setWidth(this.getWidth()) | ||
|  |   if (enabled) this.enable() | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype.enable = function () { | ||
|  |   if (!this._disabled) return | ||
|  |   this._disabled = false | ||
|  |   if (this._tty) this._enableEvents() | ||
|  |   if (this._showing) this.show() | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype.disable = function () { | ||
|  |   if (this._disabled) return | ||
|  |   if (this._showing) { | ||
|  |     this._lastUpdateAt = null | ||
|  |     this._showing = false | ||
|  |     this._doRedraw() | ||
|  |     this._showing = true | ||
|  |   } | ||
|  |   this._disabled = true | ||
|  |   if (this._tty) this._disableEvents() | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype._enableEvents = function () { | ||
|  |   if (this._cleanupOnExit) { | ||
|  |     this._removeOnExit = onExit(callWith(this, this.disable)) | ||
|  |   } | ||
|  |   this._tty.on('resize', this._$$handleSizeChange) | ||
|  |   if (this._fixedFramerate) { | ||
|  |     this.redrawTracker = setInterval(this._$$doRedraw, this._updateInterval) | ||
|  |     if (this.redrawTracker.unref) this.redrawTracker.unref() | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype._disableEvents = function () { | ||
|  |   this._tty.removeListener('resize', this._$$handleSizeChange) | ||
|  |   if (this._fixedFramerate) clearInterval(this.redrawTracker) | ||
|  |   if (this._removeOnExit) this._removeOnExit() | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype.hide = function (cb) { | ||
|  |   if (this._disabled) return cb && process.nextTick(cb) | ||
|  |   if (!this._showing) return cb && process.nextTick(cb) | ||
|  |   this._showing = false | ||
|  |   this._doRedraw() | ||
|  |   cb && setImmediate(cb) | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype.show = function (section, completed) { | ||
|  |   this._showing = true | ||
|  |   if (typeof section === 'string') { | ||
|  |     this._status.section = section | ||
|  |   } else if (typeof section === 'object') { | ||
|  |     var sectionKeys = Object.keys(section) | ||
|  |     for (var ii = 0; ii < sectionKeys.length; ++ii) { | ||
|  |       var key = sectionKeys[ii] | ||
|  |       this._status[key] = section[key] | ||
|  |     } | ||
|  |   } | ||
|  |   if (completed != null) this._status.completed = completed | ||
|  |   if (this._disabled) return | ||
|  |   this._requestRedraw() | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype.pulse = function (subsection) { | ||
|  |   this._status.subsection = subsection || '' | ||
|  |   this._status.spun++ | ||
|  |   if (this._disabled) return | ||
|  |   if (!this._showing) return | ||
|  |   this._requestRedraw() | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype._handleSizeChange = function () { | ||
|  |   this._gauge.setWidth(this._tty.columns - 1) | ||
|  |   this._requestRedraw() | ||
|  | } | ||
|  | 
 | ||
|  | Gauge.prototype._doRedraw = function () { | ||
|  |   if (this._disabled || this._paused) return | ||
|  |   if (!this._fixedFramerate) { | ||
|  |     var now = Date.now() | ||
|  |     if (this._lastUpdateAt && now - this._lastUpdateAt < this._updateInterval) return | ||
|  |     this._lastUpdateAt = now | ||
|  |   } | ||
|  |   if (!this._showing && this._onScreen) { | ||
|  |     this._onScreen = false | ||
|  |     var result = this._gauge.hide() | ||
|  |     if (this._hideCursor) { | ||
|  |       result += this._gauge.showCursor() | ||
|  |     } | ||
|  |     return this._writeTo.write(result) | ||
|  |   } | ||
|  |   if (!this._showing && !this._onScreen) return | ||
|  |   if (this._showing && !this._onScreen) { | ||
|  |     this._onScreen = true | ||
|  |     this._needsRedraw = true | ||
|  |     if (this._hideCursor) { | ||
|  |       this._writeTo.write(this._gauge.hideCursor()) | ||
|  |     } | ||
|  |   } | ||
|  |   if (!this._needsRedraw) return | ||
|  |   if (!this._writeTo.write(this._gauge.show(this._status))) { | ||
|  |     this._paused = true | ||
|  |     this._writeTo.on('drain', callWith(this, function () { | ||
|  |       this._paused = false | ||
|  |       this._doRedraw() | ||
|  |     })) | ||
|  |   } | ||
|  | } |